寻找重复数
给定一个包含 n + 1
个整数的数组 nums
,其数字都在 [1, n]
范围内(包括 1
和 n
),可知至少存在一个重复的整数。
假设 nums
只有 一个重复的整数 ,返回 这个重复的数 。
你设计的解决方案必须 不修改 数组 nums
且只用常量级 O(1)
的额外空间。
示例 1:
输入:nums = [1,3,4,2,2]
输出:2
示例 2:
输入:nums = [3,1,3,4,2]
输出:3
示例 3 :
输入:nums = [3,3,3,3,3]
输出:3
题解:
题目乍一看非常简单,但是有两个限制条件,只用常量级 O(1)
的额外空间,则不能使用哈希表,不修改 数组,则没办法进行排序或者其他操作;排除这两种想法的情况下,再考虑如何不使用 n^2 的暴力枚举优化时间复杂度其实是一件蛮困难的事情
不能只用常量级 O(1)
的额外空间
go
func findDuplicate(nums []int) int {
m := make(map[int]int)
for i := 0; i < len(nums); i++ {
if m[nums[i]] == 1 {
return nums[i]
}
m[nums[i]] = 1
}
return -1
}
不能修改 数组
go
func findDuplicate(nums []int) int {
for nums[0] != nums[nums[0]] {
nums[0], nums[nums[0]] = nums[nums[0]], nums[0]
}
return nums[0]
}
这里可以注意到,对于 1-n 的数字,有 n+1个位置,其中有一个重复的数,那么如果重复的数字为 tar,我们统计小于等于 i 的数量,只有当 i < tar 的情况下,得到的结果是等于 i 本身的,根据这个性质我们可以把 n ^ 2 的外层循环,优化为 logn
go
func findDuplicate(nums []int) int {
l, r := 0, len(nums)-1
ans := -1
for l <= r {
mid := (l + r) / 2
cnt := 0
for i := 0; i < len(nums); i++ {
if nums[i] <= mid {
cnt++
}
}
if cnt <= mid {
l = mid + 1
} else {
r = mid - 1
ans = mid
}
}
return ans
}