剑指 Offer 03. 数组中重复的数字模拟哈希表解法。
题目描述
找出数组中重复的数字。
在一个长度为 n (2 <= n <= 100000)的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
样例
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
思路
我们知道长度为n
,角标即为
[
0
,
n
−
1
]
\left[0,n-1\right]
[0,n−1]。而数据范围恰好也是
[
0
,
n
−
1
]
\left[0,n-1\right]
[0,n−1]。我们可以直接用原数组来记录数据出现的次数。
当某数字nums[i]第一次出现时,将以其为角标的元素nums[nums[i]]
变为负。当向后读取时出现nums[nums[i]] < 0
的情况,则证明nums[i]已经出现过。需要注意的是当我们访问nums[i]
为角标的元素时,nums[i]
可能已经被改为负数,访问以原值为角标的位置需要将其取绝对值nums[abs(nums[i])]
。
由于涉及到cpp里INT型没有+0
,-0
问题,题目中说必有重复元素,如果遍历结束仍然没有找到,则重复的元素是0(元素0所在的角标) ,比如以下样例。
上述说明有点过于抽象,以测试样例为例。
状态 | nums[0] | nums[1] | nums[2] | nums[3] | nums[4] | nums[5] | nums[6] |
---|---|---|---|---|---|---|---|
初始值 | 2 | 3 | 1 | 0 | 2 | 5 | 3 |
i=0 | 2 | 3 | -1 | 0 | 2 | 5 | 3 |
i=1 | 2 | 3 | -1 | -0 | 2 | 5 | 3 |
i=2 | 2 | -3 | -1 | -0 | 2 | 5 | 3 |
i=3 | -2 | -3 | -1 | -0 | 2 | 5 | 3 |
i=4 | -2 | -3 | -1 | ||||
i=5 | |||||||
i=6 |
i = 0
时,nums[i] = 2
,此时以2的绝对值(取绝对值是为了防止遍历过程中数组中元素已经被取负,导致非法访问)为角标的位置来记录2出现的次数,nums[abs(nums[i])] = nums[2]
取负。i = 1
时,nums[i] = 3
,nums[abs(nums[i])] = nums[3]
取负(由于没有+0,-0看不出变化)。i = 2
时,nums[i] = -1
,nums[abs(nums[i])] = nums[1]
取负。i = 3
时,nums[i] = 0
,nums[abs(nums[i])] = nums[0]
取负。i = 4
时,nums[i] = 2
,nums[abs(nums[i])] = nums[2]
此时已经为负数(证明其角标2
代表的元素2
出现过),故其是重复元素,返回。
代码
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
for(auto& num:nums) {
if(nums[abs(num)] < 0) return abs(num);
nums[abs(num)] *= -1;
}
return 0;
}
};
运行结果
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。