快慢指针

Posted yintianhao

tags:

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

做LeetCode碰到两个快慢指针运用的题目,记录一下,当然这个东西应用的地方肯定不止下面这两个了,以后要是碰到就再更新

快慢指针:

这里快慢实际是指他们移动的步数,一个一次移动多个位置(一般二),一个移动一个

 

1,判断链表里是否存在环

题目描述:

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

技术图片

思路:快指针和慢指针同时往链表后面移动,如果快指针到达NULL,说明链表以NULL为结尾,没有环。如果快指针追上慢指针(即两个相等),则表示有环。

代码:

技术图片
/**
 * 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;
    }
}
View Code

 

二,一个排序链表里找到中位数

这里其实就是倍数关系了,假设把快慢指针比作一条道路上的车,快车的速度是慢车的两倍,同时出发,那么快车到达终点的时候慢车就在这条路的中间位置!

但是到链表里就得注意元素个数奇偶的问题,奇数直接返回slow,偶数的话,返回slow和slow下一个数的和除2

代码:

技术图片
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)));
    }
}
View Code

 

三,输出链表的倒数第K个节点

也是跟上面差不多的原理,第一个指针从链表的头指针开始遍历向前走k-1步,第二个指针保持不动;从第K步开始,第二个指针也开始从链表的头指针开始遍历。由于两个指针的距离保持在k-1,当第一个指针到达链表的尾节点时候,第二个指针正好是倒数第K个节点

代码:

技术图片
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);
    }
}
View Code

 

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

141.Linked List Cycle 快慢指针

快慢指针问题

链表的排序(归并排序+快慢指针)

Leetcode234. 回文链表(快慢指针+反转链表)

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

LeetCode 142. 环形链表 II(逻辑环链表快慢双指针)