Article / 文章

LeetCode 第217题:存在重复元素

给你一个整数数组 nums 。如果任何值在数组中出现至少两次,返回 true ;如果数组中每个元素互不相同,返回 false 。

题目描述

给你一个整数数组 nums 。如果任何值在数组中出现至少两次,返回 true ;如果数组中每个元素互不相同,返回 false

难度

简单

题目链接

点击在LeetCode中查看题目

示例

示例 1:

输入:nums = [1,2,3,1]
输出:true

示例 2:

输入:nums = [1,2,3,4]
输出:false

示例 3:

输入:nums = [1,1,1,3,3,4,3,2,4,2]
输出:true

提示

  • 1 <= nums.length <= 10^5
  • -10^9 <= nums[i] <= 10^9

解题思路

这是一个查找重复元素的问题,有多种解决方案,以下是三种常见的方法:

方法一:哈希表(Hash Table)

最直接的方法是使用哈希表(集合或字典)来跟踪已经出现过的元素:

  1. 创建一个哈希集合,用于存储已经遍历过的数字
  2. 遍历数组,对于每个元素,检查它是否已经在哈希集合中
  3. 如果元素已经在集合中,表示存在重复,返回 true
  4. 否则,将该元素添加到集合中,继续遍历
  5. 如果遍历完整个数组都没有发现重复元素,返回 false

时间复杂度:O(n),其中 n 是数组的长度 空间复杂度:O(n),最坏情况下需要存储所有元素

方法二:排序(Sorting)

另一种方法是先对数组进行排序,然后检查相邻元素是否相同:

  1. 对数组进行排序
  2. 遍历排序后的数组,检查相邻元素是否相同
  3. 如果找到相同的相邻元素,返回 true
  4. 如果遍历完整个数组都没有发现重复元素,返回 false

时间复杂度:O(n log n),排序的时间复杂度 空间复杂度:O(1) 或 O(n),取决于排序算法的实现

方法三:计数排序(Counting Sort)

如果知道数组中元素的范围不大,可以使用计数排序的思想:

  1. 创建一个布尔数组,大小为元素的范围
  2. 遍历原数组,标记已经出现过的元素
  3. 如果发现某个元素已经被标记过,返回 true
  4. 否则,标记该元素,继续遍历
  5. 如果遍历完整个数组都没有发现重复元素,返回 false

这种方法适用于元素范围较小的情况,如果元素范围很大,会导致空间复杂度过高,不适合使用。

代码实现

C# 实现

using System;
using System.Collections.Generic;

public class Solution {
    // 方法一:哈希表
    public bool ContainsDuplicate(int[] nums) {
        HashSet<int> seen = new HashSet<int>();
        
        foreach (int num in nums) {
            if (seen.Contains(num)) {
                return true;
            }
            seen.Add(num);
        }
        
        return false;
    }
    
    // 方法二:排序
    public bool ContainsDuplicateSorting(int[] nums) {
        Array.Sort(nums);
        
        for (int i = 1; i < nums.Length; i++) {
            if (nums[i] == nums[i - 1]) {
                return true;
            }
        }
        
        return false;
    }
}

Python 实现

class Solution:
    # 方法一:哈希表
    def containsDuplicate(self, nums: List[int]) -> bool:
        seen = set()
        
        for num in nums:
            if num in seen:
                return True
            seen.add(num)
        
        return False
    
    # 方法二:排序
    def containsDuplicateSorting(self, nums: List[int]) -> bool:
        nums.sort()
        
        for i in range(1, len(nums)):
            if nums[i] == nums[i - 1]:
                return True
        
        return False
    
    # 方法三:使用Python的集合
    def containsDuplicateSet(self, nums: List[int]) -> bool:
        return len(nums) > len(set(nums))

C++ 实现

#include <vector>
#include <unordered_set>
#include <algorithm>

class Solution {
public:
    // 方法一:哈希表
    bool containsDuplicate(std::vector<int>& nums) {
        std::unordered_set<int> seen;
        
        for (int num : nums) {
            if (seen.find(num) != seen.end()) {
                return true;
            }
            seen.insert(num);
        }
        
        return false;
    }
    
    // 方法二:排序
    bool containsDuplicateSorting(std::vector<int>& nums) {
        std::sort(nums.begin(), nums.end());
        
        for (int i = 1; i < nums.size(); i++) {
            if (nums[i] == nums[i - 1]) {
                return true;
            }
        }
        
        return false;
    }
};

性能分析

各语言实现的性能对比:

实现语言 方法 执行用时 内存消耗 说明
C# 哈希表 240 ms 46.4 MB 时间复杂度 O(n),空间复杂度 O(n)
C# 排序 252 ms 46.2 MB 时间复杂度 O(n log n),空间复杂度取决于排序实现
Python 哈希表 468 ms 26.1 MB 时间复杂度 O(n),空间复杂度 O(n)
Python 排序 600 ms 25.5 MB 时间复杂度 O(n log n),空间复杂度 O(1)
Python 集合比较 444 ms 26.0 MB 时间复杂度 O(n),空间复杂度 O(n)
C++ 哈希表 88 ms 51.4 MB 时间复杂度 O(n),空间复杂度 O(n)
C++ 排序 76 ms 46.6 MB 时间复杂度 O(n log n),空间复杂度 O(1)

补充说明

代码亮点

  1. 哈希表方法在实际应用中效率更高,尤其是对于大型数组
  2. Python 的集合比较方法(len(nums) > len(set(nums)))简洁优雅,一行代码解决问题
  3. C++ 的 unordered_set 实现提供了较好的性能平衡

优化方向

  1. 对于非常大的数组,可以考虑使用并行处理,将数组分成多个部分同时处理
  2. 如果元素范围已知且较小,可以使用位图(Bitmap)来减少空间消耗
  3. 对于几乎排序的数组,可以使用自适应排序算法提高效率

解题难点

  1. 选择合适的数据结构(哈希表、排序或位图等)
  2. 权衡时间和空间复杂度
  3. 处理大数据量时的性能问题

常见错误

  1. 只检查相邻元素是否相同(需要先排序)
  2. 使用 O(n²) 的双重循环进行比较,效率低下
  3. 在使用哈希表时忘记检查元素是否已存在就直接添加
  4. 在特定语言中选择不合适的集合类型(如使用 ArrayList 代替 HashSet)

相关题目