快慢指针的应用

Posted gsh520

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了快慢指针的应用相关的知识,希望对你有一定的参考价值。

1.判断单链表是否存在环

 

 1 * Definition for singly-linked list.
 2  * public class ListNode {
 3  *     public int val;
 4  *     public ListNode next;
 5  *     public ListNode(int x) {
 6  *         val = x;
 7  *         next = null;
 8  *     }
 9  * }
10  */
11 public class Solution {
12     public bool HasCycle(ListNode head) {
13          if(head == null){
14             return false;
15         }
16         ListNode slow = head;
17         ListNode fast = head;
18         while (fast !=null && fast.next!=null){
19             slow = slow.next;
20             fast = fast.next.next;
21             if(slow == fast){
22                 return true;
23             }
24         }
25         return false;
26     }
27 }

 如果链表存在环,就好像操场的跑道是一个环形一样。此时让快慢指针都从链表头开始遍历,快指针每次向前移动两个位置,慢指针每次向前移动一个位置;如果快指针到达NULL,说明链表以NULL为结尾,没有环。如果快指针追上慢指针,则表示有环.

2.判断两个单链表是否相交,如果相交,找到他们的第一个公共节点

编写一个程序,找到两个单链表相交的起始节点。

如下面的两个链表:

技术图片

 

在节点 c1 开始相交。

 

示例 1:

技术图片

 

输入:intersectVal = 8, listA = [4,1,8,4,5], listB = [5,0,1,8,4,5], skipA = 2, skipB = 3
输出:Reference of the node with value = 8
输入解释:相交节点的值为 8 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [4,1,8,4,5],链表 B 为 [5,0,1,8,4,5]。在 A 中,相交节点前有 2 个节点;在 B 中,相交节点前有 3 个节点。

 

示例 2:

技术图片

 

输入:intersectVal = 2, listA = [0,9,1,2,4], listB = [3,2,4], skipA = 3, skipB = 1
输出:Reference of the node with value = 2
输入解释:相交节点的值为 2 (注意,如果两个列表相交则不能为 0)。从各自的表头开始算起,链表 A 为 [0,9,1,2,4],链表 B 为 [3,2,4]。在 A 中,相交节点前有 3 个节点;在 B 中,相交节点前有 1 个节点。

 

示例 3:

技术图片

 

输入:intersectVal = 0, listA = [2,6,4], listB = [1,5], skipA = 3, skipB = 2
输出:null
输入解释:从各自的表头开始算起,链表 A 为 [2,6,4],链表 B 为 [1,5]。由于这两个链表不相交,所以 intersectVal 必须为 0,而 skipA 和 skipB 可以是任意值。
解释:这两个链表不相交,因此返回 null。

这道题有三种解决方法
(1)利用快慢指针将链表1的尾结点的next赋给链表2的头结点,在循环过程中如果slow==fast则证明存在环,之后再创建一组快慢指针找到相的结点
 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode GetIntersectionNode(ListNode headA, ListNode headB) {
11         if(headA==null||headB==null)
12             return null;
13         ListNode tmp=headB;
14         while(tmp.next!=null)
15         {
16             tmp=tmp.next;
17         }
18         tmp.next=headB;
19         ListNode slow=headA;
20         ListNode fast=headA;
21         while(fast!=null&&fast.next!=null)
22         {
23             slow=slow.next;
24             fast=fast.next.next;
25             if(fast==slow)
26             {
27                 slow=headA;
28                 while(slow!=fast)
29                 {
30                     slow=slow.next;
31                     fast=fast.next;
32                 }
33                 tmp.next=null;
34                 return fast;
35             }
36         }
37         tmp.next=null;
38         return null;
39     }
40 }
(2)两链表相连
技术图片
 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode GetIntersectionNode(ListNode headA, ListNode headB) {
11         if(headA == null || headB == null) return null;
12         ListNode pA = headA, pB = headB;
13         // 在这里第一轮体现在pA和pB第一次到达尾部会移向另一链表的表头, 而第二轮体现在如果pA或pB相交就返回交点, 不相交最后就是null==null
14         while(pA != pB) {
15             pA = pA == null ? headB : pA.next;
16             pB = pB == null ? headA : pB.next;
17         }
18         return pA;
19     }
20 }
View Code

 

 (3)使两个链表长度相等,循环依次比较

3.用快慢指针获取中间结点
技术图片
 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public ListNode MiddleNode(ListNode head) {
11         ListNode slow=head;
12         ListNode fast=head;
13         if(head!=null)
14         {
15         while(fast!=null&&fast.next!=null)
16             {
17                 slow=slow.next;
18                 fast=fast.next.next;
19             }
20         }
21         
22         return slow;
23     }
24 }
View Code

通过找到中间结点的方法,也可以借此判断该链表是否是回文

 
技术图片
 1 /**
 2  * Definition for singly-linked list.
 3  * public class ListNode {
 4  *     public int val;
 5  *     public ListNode next;
 6  *     public ListNode(int x) { val = x; }
 7  * }
 8  */
 9 public class Solution {
10     public bool IsPalindrome(ListNode head) {
11         ListNode slow = head;
12             ListNode fast = head;
13             ListNode temp = head;
14             while(fast!=null&&fast.next!=null)
15             {
16                 slow = slow.next;
17                 fast = fast.next.next;
18             }
19             slow = ReverseList(slow);
20             while(slow!=null)
21             {
22                 if (temp.val != slow.val)
23                     return false;
24                 else
25                 {
26                     temp = temp.next;
27                     slow = slow.next;
28                 }
29             }
30             return true;
31     }
32     public ListNode ReverseList(ListNode head) {
33         ListNode prev = null; 
34         ListNode curr = head; 
35         while (curr != null) {
36             ListNode nextTemp = curr.next; 
37             curr.next = prev; 
38             prev = curr;
39             curr = nextTemp;
40         }
41         return prev;
42     }
43 }
View Code

 


 

以上是关于快慢指针的应用的主要内容,如果未能解决你的问题,请参考以下文章

快慢指针的应用

快慢指针

快慢指针判断链表是否有环

算法分析如何理解快慢指针?判断linked list中是否有环找到环的起始节点位置。以Leetcode 141. Linked List Cycle, 142. Linked List Cycl(代码

线性表--04---链表----常见应用场景(快慢指针约瑟夫问题)

快慢指针问题