快慢指针
做LeetCode碰到两个快慢指针运用的题目,记录一下,当然这个东西应用的地方肯定不止下面这两个了,以后要是碰到就再更新
快慢指针:
这里快慢实际是指他们移动的步数,一个一次移动多个位置(一般二),一个移动一个
1,判断链表里是否存在环
题目描述:
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数
pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果pos
是-1
,则在该链表中没有环。
思路:快指针和慢指针同时往链表后面移动,如果快指针到达NULL,说明链表以NULL为结尾,没有环。如果快指针追上慢指针(即两个相等),则表示有环。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/** * Definition for singly-linked list. * class ListNode { * int val; * ListNode next; * ListNode(int x) { * val = x; * next = null; * } * } */ public class Solution { public boolean hasCycle(ListNode head) { if (head==null) { return false; } ListNode slow = head; ListNode fast = head; while(fast!=null&&fast.next!=null) { slow = slow.next; fast = fast.next.next; if (fast==slow) { return true; } } return false; } }
二,一个排序链表里找到中位数
这里其实就是倍数关系了,假设把快慢指针比作一条道路上的车,快车的速度是慢车的两倍,同时出发,那么快车到达终点的时候慢车就在这条路的中间位置!
但是到链表里就得注意元素个数奇偶的问题,奇数直接返回slow,偶数的话,返回slow和slow下一个数的和除2
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.mine.leetcode; import java.util.List; public class Solution141 { public int getMidElement(ListNode head) { ListNode fast = head; ListNode slow = head; while(fast!=null&&slow!=null) { //System.out.println("-"+fast.val); if(fast.next==null) return slow.val; else if(fast.next!=null&&fast.next.next==null) return (slow.val+slow.next.val)/2; else { fast = fast.next.next; slow = slow.next; } } return 666; } public static ListNode generateListByArray(int[] nums) { ListNode head = new ListNode(0); ListNode temp = head; for(int i = 0;i < nums.length;i++) { temp.next = new ListNode(nums[i]); temp = temp.next; } return head.next; } public static void main(String[] args) { int[] nums = {1,2,3,4,5,6,7}; System.out.println(new Solution141().getMidElement(generateListByArray(nums))); } }
三,输出链表的倒数第K个节点
也是跟上面差不多的原理,第一个指针从链表的头指针开始遍历向前走k-1步,第二个指针保持不动;从第K步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个指针到达链表的尾节点时候,第二个指针正好是倒数第K个节点
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
package com.mine.leetcode; import java.util.List; public class Solution141 { // 查找单链表中倒数第K个结点 public ListNode GetKthNode(ListNode pHead, int k) // 函数名前面的R代表反向 { if(k == 0 || pHead == null) // 这里k的计数是从1开始的,若k为0或链表为空返回NULL return null; ListNode pAhead = pHead; ListNode pBehind = pHead; for(int i=0;i<k-1;i++){ pAhead=pAhead.next; if(pAhead==null) return null;//当链表长度小于k时候,返回Null } while(pAhead.next != null) // 前后两个指针一起向前走,直到前面的指针指向最后一个结点 { pBehind = pBehind.next; pAhead = pAhead.next; } return pBehind; // 后面的指针所指结点就是倒数第k个结点 } public static void main(String[] args) { int[] nums = {1,2,3,4,5,6,7}; System.out.println(new Solution141().GetKthNode(generateListByArray(nums), 2).val); } }