Easy
题目描述
在数字村中,有一个名为 nums 的数字列表,包含从 0 到 n-1 的整数。每个数字本应在列表中只出现一次,然而,两个调皮的数字偷偷地多出现了一次,使得列表比平常更长。
作为村里的侦探,你的任务是找到这两个调皮的数字。返回一个大小为 2 的数组,包含这两个数字(顺序任意),这样数字村就能恢复平静了。
示例 1:
输入:nums = [0,1,1,0]
输出:[0,1]
解释:数字 0 和 1 在数组中各出现两次。
示例 2:
输入:nums = [0,3,2,1,3,2]
输出:[2,3]
解释:数字 2 和 3 在数组中各出现两次。
示例 3:
输入:nums = [7,1,5,4,3,4,6,0,9,5,8,2]
输出:[4,5]
解释:数字 4 和 5 在数组中各出现两次。
约束条件:
2 <= n <= 100nums.length == n + 20 <= nums[i] < n- 输入保证
nums恰好包含两个重复元素。
解题思路
这是一个经典的寻找重复元素问题,有多种解法:
方法一:哈希表计数(推荐) 使用哈希表统计每个数字的出现次数,找出出现次数为2的两个数字。这是最直观的解法,时间复杂度为O(n),空间复杂度为O(n)。
方法二:排序法 先对数组排序,然后遍历找到相邻重复的元素。时间复杂度为O(n log n),空间复杂度为O(1)。
方法三:数学法(异或运算) 由于每个数字0到n-1应该出现一次,而有两个数字多出现了一次,可以利用异或运算的性质。但需要结合其他技巧来分离两个重复数字。
方法四:原地修改 利用数组索引,通过标记访问过的位置来找出重复元素。由于数字范围是0到n-1,可以使用负号作为标记。
考虑到代码的简洁性和可读性,推荐使用哈希表计数的方法。
代码实现
class Solution {
public:
vector<int> getSneakyNumbers(vector<int>& nums) {
unordered_map<int, int> count;
vector<int> result;
for (int num : nums) {
count[num]++;
if (count[num] == 2) {
result.push_back(num);
}
}
return result;
}
};
class Solution:
def getSneakyNumbers(self, nums: List[int]) -> List[int]:
count = {}
result = []
for num in nums:
count[num] = count.get(num, 0) + 1
if count[num] == 2:
result.append(num)
return result
public class Solution {
public int[] GetSneakyNumbers(int[] nums) {
Dictionary<int, int> count = new Dictionary<int, int>();
List<int> result = new List<int>();
foreach (int num in nums) {
if (count.ContainsKey(num)) {
count[num]++;
} else {
count[num] = 1;
}
if (count[num] == 2) {
result.Add(num);
}
}
return result.ToArray();
}
}
var getSneakyNumbers = function(nums) {
const seen = new Set();
const result = [];
for (const num of nums) {
if (seen.has(num)) {
result.push(num);
} else {
seen.add(num);
}
}
return result;
};
复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 哈希表计数 | O(n) | O(n) |
| 排序法 | O(n log n) | O(1) |
| 原地修改 | O(n) | O(1) |
其中 n 是数组的长度。哈希表方法在时间效率上最优,适合大多数场景。
相关题目
- . Find All Duplicates in an Array (Medium)