https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/
首先一个很重要的信息是在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内,第二个就是数组中重复数字的次数不确定,但肯定至少重复两次
这道题好像加了很多测试样例,
sort
直接sort一遍,然后for循环逐个判断即可
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
nums.sort()
ans=0
for i in range(len(nums)-1):
if nums[i]==nums[i+1]:
ans = nums[i]
return ans
hash
开一个等长的数组,然后一个for判断
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
appeared=set()
for num in nums:
if num in appeared:
return num
appeared.add(num)
修改原数组作为标记
由于num的范围在0~n-1,我们可以改变nums的值,来标记这个元素是否之前出现过
例如[2, 3, 1, 0, 2, 5, 3]
我们先把它逐个+1
0 1 2 3 4 5 6
3 5 2 1 3 6 4
i
3 5 2 -1 3 6 4
i
3 5 2 -1 3 -6 4
i
3 5 -2 -1 3 -6 4
i
-3 5 -2 -1 3 -6 4
i 此时找到一个为负的数-1 返回当前的值-1
-3 5 -2 1 3 6 4
由于遍历过程中数字可能会小于0,所以我们需要取到abs
并且0是没有负数的,所以我们要先+1再遍历,否则通不过0 1 0 这种测试样例
nums=list(map(lambda x:x+1,nums))
for i in range(len(nums)):
if(nums[abs(nums[i])-1]<0):
return abs(nums[i])-1
nums[abs(nums[i])-1]=-nums[abs(nums[i])-1]
另外之前要加1,因为 [0,1,0]这种状况0不能修改成负数,所以要把数组的每个num加1,在遍历的时候取下标再返回
利用输入数据的性质
输入数据有一个特点:所有数字都在 0~n-1 的范围内
按照这个数据的特点,我们可以得知下面两个性质
假如一个数组没有重复我们知道排序后每个数字都在它唯一的位置,如0 1 2 3 4 5
假如有一个2重复了,那么他就会挤占其它的位置 0 1 2 2 4 5
那么我们想办法判断每个元素是否在它的原来位置就行了
假设当前的值是n,下标是i,那么它最终的位置一定在n上(看上面的例子)
我们对数组进行遍历,一共有这几种情况
- 当前的数字不在最终位置上,判断最终位置的数字
- 是否和当前数字相同,如果相同则发生了冲突,说明当前数字是重复数字
- 如果不相同,那么可以放心的交换,此时下标i不会走,以防漏掉数字
- 当前位置在最终位置上,下标i直接+1
0 1 2 3 4 5 6
2 3 1 0 2 5 3
1: 2 3 1 0 2 5 3
i
2: 1 3 2 0 2 5 3
i
3: 3 1 2 0 2 5 3
i
4: 0 1 2 3 2 5 3
i i i i i
此时发现2冲突了,返回重复数字2
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
i=0
while i<len(nums):
if nums[i]!=i: #不在最终位置
if nums[i]!=nums[nums[i]]: #不相等
nums[nums[i]],nums[i]=nums[i],nums[nums[i]]
else: #冲突
return nums[i]
else:
i+=1
扩展
leetcode上面这一类题目很像,都是一样的思想,把数组本身当作hash表
https://leetcode-cn.com/problems/find-the-duplicate-number/
https://leetcode-cn.com/problems/first-missing-positive/
https://leetcode-cn.com/problems/find-all-duplicates-in-an-array/
https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array/