Contains Duplicate(存在重复元素)
题目 / Problem
中文: 给定一个整数数组 nums,如果数组中任意一个值至少出现两次,返回 true;如果每个元素都互不相同,返回 false。
English: Given an integer array nums, return true if any value appears at least twice in the array, and return false if every element is distinct.
示例 / Examples
Example 1
Input: nums = [1,2,3,1]
Output: true
解释 / Explanation:
元素 1 出现在下标 0 和 3。
The element 1 occurs at indices 0 and 3.
Example 2
Input: nums = [1,2,3,4]
Output: false
解释 / Explanation:
所有元素都互不相同。
All elements are distinct.
Example 3
Input: nums = [1,1,1,3,3,4,3,2,4,2]
Output: true
约束 / Constraints
1 <= nums.length <= 10⁵-10⁹ <= nums[i] <= 10⁹
解题思路:哈希集合 / Approach: Hash Set
使用 Set 保存已经遍历过的元素。对于每个元素 num:
Use a Set to store elements already visited. For each num:
- 如果集合中已经存在
num,说明它至少是第二次出现,立即返回true。
Ifnumis already in the set, it has appeared at least twice, so returntrueimmediately. - 否则,将
num加入集合并继续遍历。
Otherwise, addnumto the set and continue. - 如果遍历结束仍未发现重复元素,返回
false。
If traversal finishes without finding a duplicate, returnfalse.
集合只关心某个值是否出现过,不需要记录具体出现次数,因此比使用频率 Map 更直接。
The set only needs to know whether a value has appeared before; exact frequencies are unnecessary, making it more direct than a frequency Map.
JavaScript 实现 / JavaScript Implementation
/**
* @param {number[]} nums
* @return {boolean}
*/
function containsDuplicate(nums) {
const seen = new Set();
for (const num of nums) {
if (seen.has(num)) {
return true;
}
seen.add(num);
}
return false;
}
执行过程 / Walkthrough
以 nums = [1,2,3,1] 为例:
For nums = [1,2,3,1]:
| 下标 / Index | 当前值 / num | 检查前的 seen | 是否存在 / Exists? | 操作 / Action |
|---|---|---|---|---|
| 0 | 1 | {} | No | 加入 1 / Add 1 |
| 1 | 2 | {1} | No | 加入 2 / Add 2 |
| 2 | 3 | {1, 2} | No | 加入 3 / Add 3 |
| 3 | 1 | {1, 2, 3} | Yes | 返回 true / Return true |
遇到第二个 1 时即可确定数组包含重复元素,无需继续处理。
Upon reaching the second 1, the duplicate is confirmed and no further processing is necessary.
对于 nums = [1,2,3,4],所有元素都会成功加入集合,遍历结束后返回 false。
For nums = [1,2,3,4], every element is added successfully, so return false after traversal.
复杂度 / Complexity
设数组长度为 n。
Let the array length be n.
- 时间复杂度:平均为
O(n),每个元素最多执行一次集合查询和插入。
Time:O(n)on average, because each element requires at most one set lookup and insertion. - 空间复杂度:
O(n),最坏情况下所有元素都不同,需要全部保存到集合中。
Space:O(n), because all elements may be distinct and stored in the set.
简洁写法 / Concise Version
利用 Set 自动去重的性质,可以比较去重前后的元素数量:
Because a Set automatically removes duplicates, compare the element counts before and after deduplication:
function containsDuplicateConcise(nums) {
return new Set(nums).size !== nums.length;
}
- 时间复杂度 / Time: 平均
O(n)/O(n)on average - 空间复杂度 / Space:
O(n)
这种写法更短,但必须先构造完整集合,无法在发现早期重复元素时立即结束。
This version is shorter but always constructs the complete set and cannot stop early when a duplicate appears near the beginning.
排序解法 / Sorting Approach
排序后,相同元素一定相邻,只需检查相邻元素是否相等:
After sorting, equal values become adjacent, so compare neighboring elements:
function containsDuplicateBySorting(nums) {
nums.sort((a, b) => a - b);
for (let i = 1; i < nums.length; i++) {
if (nums[i] === nums[i - 1]) {
return true;
}
}
return false;
}
- 时间复杂度 / Time:
O(n log n) - 空间复杂度取决于排序实现。
Space: Depends on the sorting implementation. - 该写法会修改原数组中元素的顺序。
This approach changes the order of elements in the original array.
哈希集合的平均时间复杂度更低,并且不会修改输入数组。
The hash-set solution has better average time complexity and does not modify the input array.
暴力解法的问题 / Problem with Brute Force
枚举所有元素对并判断它们是否相等,需要 O(n²) 时间。当数组长度达到 10⁵ 时,该解法会超时。
Checking every pair for equality takes O(n²) time. With up to 10⁵ elements, this approach will time out.
易错点 / Common Pitfalls
- “至少出现两次”意味着只要发现一个重复值就可以返回
true。
“Appears at least twice” means one repeated value is enough to returntrue. - 应先检查集合,再添加当前元素;这样逻辑最清晰。
Check the set before adding the current element for the clearest logic. - 不需要统计每个值的完整出现次数。
There is no need to count the complete frequency of every value. - JavaScript 数值排序必须传入
(a, b) => a - b,否则默认按字符串顺序排列。
Numeric sorting in JavaScript requires(a, b) => a - b; otherwise values are sorted lexicographically. - 排序解法会改变原数组,而集合解法不会。
The sorting approach modifies the original array; the set approach does not.