03 数组中的重复数字
题目
解题方法
法一 暴力求解 时间:O(n) 空间:O(1)
算法流程
暴力求解,对数组进行排序,判断相邻元素是否相等,如果相等则输出不相等则继续
复杂度
时间复杂度O(n):内置sort函数O(nlogn), for循环遍历数组O(n)
空间复杂度O(1): 使用常数pre复杂度的额外空间
代码
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
nums.sort()
pre =-1
for i in nums:
if i==pre:
return i
pre=i
法二 哈希表 时间:O(n) 空间:O(n)
算法流程
- 初始化: 新建 HashSet ,记为 dic ;
- 遍历数组 nums 中的每个数字 num :
当 num 在 dic 中,说明重复,直接返回 num ;
将 num 添加至 dic 中; - 返回 −1 。本题中一定有重复数字,因此这里返回多少都可以。
复杂度
时间复杂度O(n):for循环遍历数组O(n),哈希查找添加O(1)
空间复杂度O(n): 使用dict 复杂度O(n)
代码
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
dict={}
for i in nums:
if i not in dict:
dict[i]=1
else:
return i
法三 原地哈希 时间:O(n) 空间:O(1)
算法流程
题目中长度为n,则索引为0n-1,而nums中数字的取值范围又在0n-1,因此没有重复的情况下我们就可以让索引和数值一一对应,如果有重复则某一个索引会对应已经出现过的数值,因此找重复数字的算法流程为:
- 遍历数组 nums ,设索引初始值为 i=0 :
- 判断nums[i]与i是否相等
若 nums[i]=i : 说明此数字已在对应索引位置,无需交换,继续循环;
若不相等就去找nums[nums[i]]对应的值 - 判断nums[nums[i]]与nums[i]是否相等
如果nums[nums[i]]=nums[i],那么数组的第i位和第nums[i]位数值相等,返回重复的数字nums[i]
如果nums[nums[i]]!=nums[i],那么就交换第i位和第nums[i]位的数值,起码让第nums[i]位的值=nums[i] - 若遍历完毕尚未返回,则返回 −1 。
复杂度
时间复杂度O(n):for循环遍历数组O(n),每轮遍历判断和交换O(1)
空间复杂度O(1): 使用常数复杂度的额外空间
代码
class Solution:
def findRepeatNumber(self, nums: List[int]) -> int:
n=len(nums)
for i,num in enumerate(nums):
while nums[i]!=i:
m=nums[i]
#if nums[nums[i]]==nums[i]做判断会陷入死循环,把nums[i]提前保存出来
if nums[m]==m:
return m
nums[i]=nums[m]
nums[m]=m