文章目录
1. 题目信息
1.1 题目描述
题目链接: https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
1.2 测试用例
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
2. 题目分析
2.1 找重复的常规思路
- 在
无序
的数据中寻找重复, 需要两层循环, 最坏情况下时间复杂度 O ( N 2 ) O(N^2) O(N2) ; - 在
有序
的数据中寻找重复, 时间复杂度为排序的 O ( N ∗ l o g N ) O(N*logN) O(N∗logN) + 单次查找的 O ( N ) O(N) O(N) , 最终为 O ( N ∗ l o g N ) O(N*logN) O(N∗logN) ;
2.2 用hash表判定重复
直接遍历 一边检查每个数字之前是否出现过, 一边存储每个新出现的数字;
- 在
Python
中可以使用set/dict
等数据结构; - 在
C++
中可以使用unordered_set/unordered_map
等数据结构;
2.3 充分利用题目给定的数字区间
注意给定的数字 n 个, 取值范围 0 ~ n-1, 那么没有重复的话, 通过一定的次序交换可以让每个数字 i 都放在对应的下标 i 的位置, 如果出现该位置已经有一个值为 i 的数字, 则说明该数字重复啦;
- 遍历数组, 判定当前下标 i 位置的值
nums[i]
和i
是否相等; - 如果相等则继续检查下一个;
- 如果不相等, 则将检查是否能够将
nums[i]
放到nums[nums[i]]
下面取;- 如果目标位置的值已经和下标相等, 说明当前这个数字
nums[i]
重复了, 直接返回; - 否则, 将当前位置的值
nums[i]
和nums[nums[i]]
进行互换, 然后重复本轮的步骤;
- 如果目标位置的值已经和下标相等, 说明当前这个数字
3. 代码详情
3.1 C++
3.1.1 sort方法
// 执行用时:48 ms, 在所有 C++ 提交中击败了56.43%的用户
// 内存消耗:22.5 MB, 在所有 C++ 提交中击败了6.93%的用户
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
sort(nums.begin(), nums.end());
for (int i = 1; i < nums.size(); i++) {
if (nums[i] == nums[i-1]) {
return nums[i];
}
}
return 0; // 不应该运行到此处;
}
};
3.1.2 hash方法
// 执行用时:60 ms, 在所有 C++ 提交中击败了34.11%的用户
// 内存消耗:26.9 MB, 在所有 C++ 提交中击败了17.77%的用户
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
unordered_set<int> seen;
for (auto &n : nums) {
if (seen.find(n) != seen.end()) {
return n;
} else {
seen.insert(n);
}
}
return 0; // should not run to here
}
};
3.1.3 位置交换
// 执行用时:60 ms, 在所有 C++ 提交中击败了4.11%的用户
// 内存消耗:22.4 MB, 在所有 C++ 提交中击败了72.96%的用户
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
for (int i = 0; i < nums.size(); i++) {
while (nums[i] != i) {
if (nums[nums[i]] == nums[i]) {
return nums[i];
}
swap(nums[i], nums[nums[i]]);
}
}
return 0;
}
}
3.2 Python
3.2.1 sort排序
# 执行用时:36 ms, 在所有 Python3 提交中击败了99.17%的用户
# 内存消耗:23.4 MB, 在所有 Python3 提交中击败了41.35%的用户
def findRepeatNumber(self, nums: List[int]) -> int:
nums.sort()
for i in range(1, len(nums)):
if nums[i] == nums[i-1]:
return nums[i]
return 0
3.2.2 用set
# 执行用时:52 ms, 在所有 Python3 提交中击败了66.63%的用户
# 内存消耗:23.4 MB, 在所有 Python3 提交中击败了49.95%的用户
def findRepeatNumber(self, nums: List[int]) -> int:
seen = set()
for n in nums:
if n in seen:
return n
seen.add(n)
return 0
3.2.3 位置交换
'''
执行用时:48 ms, 在所有 Python3 提交中击败了81.38%的用户
内存消耗:23.5 MB, 在所有 Python3 提交中击败了12.97%的用户
执行用时:40 ms, 在所有 Python3 提交中击败了96.78%的用户
内存消耗:23.3 MB, 在所有 Python3 提交中击败了74.64%的用户
'''
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
for i, n in enumerate(nums):
while i != n:
if nums[n] == n:
return n # 该数字重复了
nums[i], nums[n] = nums[n], nums[i]
n = nums[i]
return 0
居然排序是最快的 😃