剑指 Offer 03. 数组中重复的数字
剑指 Offer 03. 数组中重复的数字
题目
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
限制:
2 <= n <= 100000
方法一:用HashSet
复杂度分析:
- 时间复杂度 O(N) : 遍历数组使用 O(N) ,HashSet 添加与查找元素皆为 O(1) 。
- 空间复杂度 O(N) : HashSet 占用 O(N) 大小的额外空间。
Code:
class Solution {
public int findRepeatNumber(int[] nums) {
int len = nums.length;
HashSet<Integer> set = new HashSet<>();
for (int x : nums) {
if (set.contains(x)) return x;
set.add(x);
}
return 0;
}
}
方法二:原地交换
思路:
题目说一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内
,那么数组元素的索引
和值
应该是一对多
的关系,因此,可遍历数组并通过交换操作,使元素的 索引 与 值 对应(即 nums[i]=i )
在遍历中,第一次遇到数字
通俗易懂的解释:
这个原地交换法就相当于分配工作,每个索引代表一个工作岗位,每个岗位必须专业对口,既0索引必须0元素才能上岗。而我们的目的就是找出溢出的人才,既0索引岗位有多个0元素竞争。
我们先从0索引岗位开始遍历,首先我们看0索引是不是已经专业对口了,如果已经专业对口既nums[0]=0,那我们就跳过0岗位看1岗位。如果0索引没有专业对口,那么我们看现在0索引上的人才调整到他对应的岗位上,比如num[0]=2,那我们就把2这个元素挪到他对应的岗位上既num[2],这个时候有两种情况:1、num[2]岗位上已经有专业对口的人才了,既num[2]=2,这就说明刚刚那个在num[0]上的2是溢出的人才,我们直接将其返回即可。2、num[2]上的不是专业对口的人才,那我们将num[0]上的元素和num[2]上的元素交换,这样num[2]就找到专业对口的人才了。之后重复这个过程直到帮num[0]找到专业对口的人才,然后以此类推帮num[1]找人才、帮num[2]找人才,直到找到溢出的人才。
算法流程:
- 遍历数组nums,设初始索引值为i=0;
- 若
说明此数字已在对应索引位置,无需交换,因此跳过 ; - 若
:代表索引 处和索引 处的元素都为 ,找到一组重复值,返回该值 ; - 否则:交换索引为
和 的元素值,将此数字交换至对应索引位置。
- 若
- 若遍历完毕尚未返回,则返回-1。
复杂度分析:
- 时间复杂度 O(N) : 遍历数组使用 O(N) ,每轮的判断和交换操作使用O(1)。
- 空间复杂度 O(1) : 使用常熟复杂度的额外空间。
Code:
class Solution {
public int findRepeatNumber(int[] nums) {
int len = nums.length;
int i = 0;
while (i < len) {
if (nums[i] == i) {
i++;
continue;
}
if (nums[nums[i]] == nums[i]) return nums[i];
int temp = nums[i];
nums[i] = nums[temp];
nums[temp] = temp;
}
return -1;
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· winform 绘制太阳,地球,月球 运作规律
· 上周热点回顾(3.3-3.9)