Leetcode287. 寻找重复数(数组模拟链表的快慢指针法)

Posted xdcat

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode287. 寻找重复数(数组模拟链表的快慢指针法)相关的知识,希望对你有一定的参考价值。

寻找重复数

技术图片

根据题意,数组中的数字都在1~n之间,所以数字的范围是小于数组的范围的,数组的元素可以和数组的索引相联系。

例如:nums[0] = 1 即可以将nums[0]作为索引 通过nums[0] 可以访问到nums[1],以此类推。

技术图片

如左图所示,环的入口就是重复元素。

那么问题就转化为了如何找到入环的第一个节点的问题。时间复杂度为O(n)

慢指针可以定义为:nums[slow] 快指针可以定义为:nums[nums[fast]]

 1 class Solution {
 2     public int findDuplicate(int[] nums) {
 3         int slow = 0;
 4         int fast = 0;
 5         slow = nums[slow];
 6         fast = nums[nums[fast]];
 7         while(slow != fast){
 8             slow = nums[slow];
 9             fast = nums[nums[fast]];
10         }
11         fast = 0;
12         while(slow != fast){
13             fast = nums[fast];
14             slow = nums[slow];
15         }
16         return slow;
17     }
18 }

【下面顺便复习一下关于链表的题】

环形链表

141. 环形链表

1. 判断是否有环的思路:使用快慢指针。快指针走两步,慢指针走一步,最终快慢指针在环上相遇,且绕圈小于两圈。
 1 public class Solution {
 2     public boolean hasCycle(ListNode head) {
 3         if(head == null || head.next == null || head.next.next == null){
 4             return false;
 5         }
 6         ListNode slow = head.next;
 7         ListNode fast = head.next.next;
 8         while(slow != fast){
 9             if(fast.next == null || fast.next.next == null){
10                 return false;
11             }
12             slow = slow.next;
13             fast = fast.next.next;
14         }
15         return true;
16     }
17 }

142. 环形链表 II

2. 寻找入环第一个节点:使用快慢指针。快指针走两步,慢指针走一步,一起走到相遇节点后,慢指针不动,快指针回到原点,然后快慢指针再一起一步一步地走,相遇点即入环的第一个节点。

 1 public class Solution {
 2     public ListNode detectCycle(ListNode head) {
 3         if(head == null || head.next == null|| head.next.next == null){
 4             return null;
 5         }
 6         ListNode slow = head.next;
 7         ListNode fast = head.next.next;
 8         while(slow!=fast){
 9             if(fast.next == null || fast.next.next == null){
10                 return null;
11             }
12             slow = slow.next;
13             fast = fast.next.next;
14         }
15         fast = head;
16         while(slow != fast){
17             slow = slow.next;
18             fast = fast.next;
19         }
20         return slow;
21     }
22 }

相交链表

3. 找出两个链表相交的第一个节点
两个链表的三种可能情况:
  1. 一个有环,一个无环:不可能相交
  2. 两个都无环:需要判断是否相交。相交,则是第一个相交节点。不相交,返回null。
  3. 两个都有环
    1. 两个各自一个环:不相交,返回null
    2. 两个共用一个环
      1. 先找入环的第一个节点 loop1和loop2
      2. 入环节点一样:loop1==loop2 可以转化为无环的相交问题,终止节点变成了loop节点。
      3. 入环节点不一样:loop1继续向下走直到遇到loop2,如果没有遇到则是两个各自一个环。返回loop1或loop2。
 
两个都无环相交的情况:
思路:如果两个链表相交,那么末尾的节点一定是同一个,因为一个节点只有一个出度。假设长链表长len1,短链表长len2,长链表先走len1-len2步,短链表从回到起点跟着一起走,相遇点即交点。
 1 public class Solution {
 2     public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
 3         ListNode curA = headA;
 4         ListNode curB = headB;
 5         int lenA = 0, lenB = 0;
 6         while(curA != null){
 7             curA = curA.next;
 8             lenA ++;
 9         }
10         while(curB != null){
11             curB = curB.next;
12             lenB ++;
13         }
14         //A始终是长链表
15         curA = lenA > lenB ? headA:headB;
16         curB = curA == headA? headB:headA;
17         int del = Math.abs(lenA - lenB);
18         while(del > 0){
19             curA = curA.next;
20             del--;
21         }
22         while(curA!=curB){
23             if(curA.next == null || curB.next == null){
24                 return null;
25             }
26             curA = curA.next;
27             curB = curB.next;
28         }
29         return curA;
30     }
31 }

 两个都有环相交的情况:

 【待续】

以上是关于Leetcode287. 寻找重复数(数组模拟链表的快慢指针法)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode#287-寻找重复数

LeetCode:寻找重复数287

leetcode.数组.287寻找重复数-Java

LeetCode287. 寻找重复数

LeetCode287. 寻找重复数

LeetCode 287. 寻找重复数