【怒撕剑指Offer】系列旨在用最通俗易懂的语言与动画讲解算法,培养逻辑思维,让你在互联网面试过程中不再畏惧手撕算法。
1 题目描述
在一个长度为 n
的数组里,所有的数字都在 0 ~ n-1
的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。找出数组中任意一个重复的数字。
输入:[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
2 解题思路
首先可以考虑排序,先对原数组进行排序,之后遍历数组找到重复数字,时间复杂度 ,但这显然不是最优解;此外哈希表也能够解决,额外创建一个哈希表,将数组中的数字逐个放入哈希表中,只需遍历一次即可找到重复数字,时间复杂度 ,额外空间复杂度 ;
不过还有一种时间复杂度为 且额外空间复杂度为 的最优解法。
利用数组中的数字都在 0 ~ n-1
的范围内这一条件,如果数组中没有重复的数字,那么当数组排序后数字 i
都将会出现在下标为 i
的位置。如果有重复数字,就出现不止一个数字 i
出现在下标为 i
的位置,利用这一原理可以求解。
3 动图演示
4 代码
4.1 Java
public static int findRepeatNumber(int[] nums) {
if (nums == null || nums.length == 0) {
return -1;
}
for (int i = 0; i < nums.length; i++) {
while (nums[i] != i && nums[nums[i]] != nums[i]) {
swap(nums, i, nums[i]);
}
if (nums[i] != i) {
return nums[i];
}
}
return -1;
}
public static void swap(int[] nums, int i, int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
4.2 Go
func findRepeatNumber(nums []int) int {
for idx, val := range nums{
if idx == val{
continue
}
if nums[val] == val{
return val
}
nums[val], nums[idx] = nums[idx], nums[val]
}
return 0
}