- 寻找重复数
二分法
假设重复值大于m,那么小于等于m的值的数量一定 ≥ \geq ≥m。
func findDuplicate(nums []int) (ans int) {
n:= len(nums)
min,max:=1,n
for min<max{
m:=(min+max)/2
cnt:=0
for _,v:=range nums{
if v<=m{
cnt++
}
}
if cnt>m{
max=m
}else{
min=m+1
}
}
return min
}
龟兔赛跑
将不重复的组数的值作为下一步的索引可以形成一个类似链表的结构。
如果存在一对重复值就会成环。
利用快慢指针来寻找环入口P2。
快慢指针同时从P1出发,慢指针一次走一步,快指针一次走两步。
假设两个指针在P3相遇,则有:
2
×
(
a
+
b
)
=
a
+
k
×
(
b
+
c
)
+
b
2×(a+b)=a+k×(b+c)+b
2×(a+b)=a+k×(b+c)+b
所以
a
+
b
=
k
×
(
b
+
c
)
a+b=k×(b+c)
a+b=k×(b+c)
如果将快指针放到起点P1,和慢指针一起往前走a步。
则快指针的位置到了P2,
而慢指针的位置为:
a
+
k
×
(
b
+
c
)
+
b
+
a
=
a
+
2
k
×
(
b
+
c
)
a+k×(b+c)+b+a=a+2k×(b+c)
a+k×(b+c)+b+a=a+2k×(b+c)
恰好也到了P2,所以两个指针下一次相遇的地方就是环的入口。
这就是龟兔赛跑算法精巧的地方。
func findDuplicate(nums []int) (ans int) {
nums=[]int{1,3,4,2,2}
slow,fast:=0,0
slow=nums[slow]
fast=nums[nums[fast]]
for nums[slow]!=nums[fast]{
slow=nums[slow]
fast=nums[nums[fast]]
}
slow=0
fast=nums[fast]
fmt.Println(nums)
for slow!=fast{
slow=nums[slow]
fast=nums[fast]
}
fmt.Println(nums)
return nums[slow]
}