版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a247027417/article/details/83541073
之前写了一篇Duplicate Number的博客了,和学长讨论的时候发现,原来的解是一个错误解。虽然可以提交而且时间复杂度很小,但是不满足不修改原数组的条件。那一篇博客详见Duplicate Number 错误blog
【解析】
将找重复值变成寻找环形链表的入口节点问题
一个n+1长的数组中放置1到n,一定会出现相同的数字。因为数组中的变量和数组下标的关系,可以联想到,将数组看成一个链表。数组中的值是链表中节点存储的值,同时也代表了next的位置。
比如 : nums=[1, 3, 5, 5, 4, 2] ,首先是1,所以节点数据为1,next的下标为1,第二个节点为nums[1]=3,next的下标为3,第三个节点为nums[3]=5,next的下标为5,第四个节点的数据为nums[5]=2,next的下标为2,第五个节点为nums[2]=5,下一个next的下标为5,形成了环。可以看成链表, 1->3->5->2->5,而成环的这个节点,就是重复出现的值,因此,这道题变成寻找环的入口。(注意:之所以可以看成环,是因为不存在0,如果0出现在数组下标为0的位置,就不能这么做)
寻找环形列表入口
整体步骤
1. 设置快慢指针,快指针每次步进2个,慢指针每次步进1个。
2. 当快慢指针第一次相遇时,到达图中红点,此时将快指针至回原点,同时设置其步长为1个
3. 当快慢指针再次相遇时,输出环形入口值,即为重复值
代码
public class Solution4 {
public int findDuplicate(int[] nums) {
if(nums.length <= 1)
return -1;
// Ptr_slow 和Ptr_fast设置的值为其走了一步之后的值,不然需要在while中判断两者为0的情况
int Ptr_slow = nums[0];
int Ptr_fast = nums[nums[0]];
// 找到红点
while(Ptr_slow!=Ptr_fast)
{
Ptr_slow = nums[Ptr_slow];
Ptr_fast = nums[nums[Ptr_fast]];
}
// 将快指针至回原点,步长变1
Ptr_fast = 0;
while(Ptr_slow != Ptr_fast)
{
Ptr_slow = nums[Ptr_slow];
Ptr_fast = nums[Ptr_fast];
}
return Ptr_fast;
}
}