快慢指针的应用
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 }
(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 }
通过找到中间结点的方法,也可以借此判断该链表是否是回文
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 }
以上是关于快慢指针的应用的主要内容,如果未能解决你的问题,请参考以下文章
算法分析如何理解快慢指针?判断linked list中是否有环找到环的起始节点位置。以Leetcode 141. Linked List Cycle, 142. Linked List Cycl(代码