Day4:剑指 Offer 03. 数组中重复的数字(简单)

题目

找出数组中重复的数字。

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

示例 1:

输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3 

限制:

  • 2 <= n <= 100000

来源:力扣(LeetCode)

链接:https://leetcode.cn/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

方法一:哈希表

我们可以利用哈希表中的Count函数来快速的找到数组元素nums[i]是否出现。一次遍历中,如果元素未曾出现,则将该元素加入哈希表;如果已经出现,直接返回重复元素即可。

由于题目说,存在多个重复元素,只需找到任意一个,我们的这种方法找到的是第一个出现的重复元素。

AC代码

时空复杂度

经典空间换时间。

时间复杂度:最坏情况,也就是重复元素在最后一位,此时为O(N)。

空间复杂度:同上,O(N)。

方法二:数组排序

要想在不开辟额外的内存空间情况下,实现题目要求,我们可以先对数组进行一个排序(题目没说不能改变原数组),之后遍历排序数组,遇到重复元素则返回即可。

AC代码

时空复杂度

时间复杂度:排序的平均时间复杂度为O(NLogN)

空间复杂度:O(1)

方法三:辅助数组

在方法二中,我们使用了排序的方法先对数组进行预处理。其实,我们还有个题目条件没有用到:数组 nums 里的所有数字都在 0~n-1 的范围内。根据这个信息,我们可以想到一个新方法:

  • 开辟一个长度为n的数组res,初始化所有元素为0

  • 对nums遍历,nums[i]作为下标pos,将res中pos对应的值加一,也就是res[pos]++

  • 退出条件:如果res[pos]为1,说明已有重复元素。

AC代码

时空复杂度

时间复杂度:O(N)

空间复杂度:O(N)

方法四:辅助数组进阶(原地)

我们可以将前三种方法对应的时空复杂度列表对比:

方法

哈希表

排序

辅助数组

时间复杂度

O(N)

O(NlogN)

O(N)

空间复杂度

O(N)

O(1)

O(N)

可以看到,排序的时间复杂度最高,但是空间复杂度最低。有没有一种方法,可以做到又快又省内存呢?

答案是可以。

依然是盯着:数组 nums 里的所有数字都在 0~n-1 的范围内,这个重要信息。我们可不可以将元素放到数组中正确的位置中去? 例如:

输入:
[2, 3, 1, 0, 2, 5, 3]

数组下标为0的元素为2 而数组下标为2的元素为1。 我们将其交换,就把元素2放到了下标正确的位置:

[1, 3, 2, 0, 2, 5, 3]

此时,数组下标为0的元素为1,而数组下标为1的元素为3。 继续交换,就把元素1放到了下标正确的位置:

[3, 1, 2, 0, 2, 5, 3]

如此循环,直到待交换的元素和下标对应位置上的元素重复,即nums[nums[i]]==nums[i] 则说明我们已经找到了重复元素。

AC代码

时空复杂度

时间复杂度:看似有两个while循环,实际上的时间复杂度为O(N)

空间复杂度:原地操作,O(1)

备注

对上述四种方法。如果题目没有说到数组元素在0~n-1之间,就只能使用哈希表或者排序方法。

或者如果不能对数组进行改变,则只能使用辅助空间的方法。大家可以自己随机应变。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值