leetcode记录-142-环形链表Ⅱ-双指针

142.环形链表Ⅱ

在这里插入图片描述

思路

  1. 数学推导:①先看是否有环:采用快慢指针的方式,如果俩指针能相遇,证明有环。要是前面的指针为null或者前面指针的next为null,就证明无环。②找入口:按照数学推导,设环长为n,则在相遇点快指针比慢指针多走了an步,而其步数为慢指针的2倍,所以慢指针走了an步。假设从头节点到入口节点要走m步,则慢指针再走m步就能到入口(因为再走m步,慢指针一共走了m+a*n步,即走到了入口——因为正好是头节点走到入口,再绕环走a圈还是回到了入口),但是我们不知道这个m为多少,但是我们知道头节点到入口走m步,慢节点再走m步也能到入口,所以一个节点从头节点开始,和慢节点一起每次前进一步,当两个节点相遇时,就是入口节点。
  2. 相对直接暴力的方法:①先看是否有环:同上。②再看环里的节点数目:因为快慢指针相遇节点一定在环内,从此点开始步进,记录步数,当再次回到此节点得到的步数即环长。③寻找“形状尾巴”倒数第n个节点即为环入口(形状尾巴即第一个next为前面节点的节点):此步方法类似无环链表求倒数第n个节点,只不过无环链表循环结束条件是first.next==null,有环链表的循环结束条件时first.next==second(first开始为head节点,然后向后移动n-1个;second为头节点,两者一起步进,知道满足循环结束条件)

代码

  1. 数学推导:
public class Solution {
    public ListNode detectCycle(ListNode head) {
        ListNode first = head;
        ListNode second = head;
        while(true){
            if (first==null||first.next==null) return null;
            first=first.next.next;
            second=second.next;
            if (first==second) break;
        }
        first=head;
        while (true){
            if (first==second) break;
            first=first.next;
            second=second.next;
        }
        return first;
    }
}
  1. 稍暴力(是否有环+环长+倒数第n个节点):
public class Solution {
    public ListNode detectCycle(ListNode head) {
        //证明有环
        ListNode first = head;
        ListNode second = head;
        while(true){
            if (first==null||first.next==null) return null;
            first=first.next.next;
            second=second.next;
            if (first==second) break;
        }
        //获得环结点数
        int num=0;
        while(true){
            second=second.next;
            num++;
            if (second==first) break;
        }
        //寻找链表倒数第num个节点(倒数第num个节点的思想,如果为无环列表最后让first.next==null停止循环,有环让first.next==second即可,因为移动之后second指向入口)
        first=head;
        second=head;
        while (num>1){ //移动n-1个
            num--;
            first=first.next;
        }
        while(true){
            if (first.next==second) break;
            first=first.next;
            second=second.next;
        }
        return second;
    }
}

技巧+总结

  1. 链表节点类:
public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}
  1. 链表题目一般都是使用双指针法解决的,例如寻找距离尾部第K个节点、寻找环入口、寻找公共尾部入口等。
  2. 循环条件不好写,如本题如果判断有无环的时候循环条件写为while(first==second)会出现这个情况永远无法满足,使得循环一直进行下去的情况,使用while(1),然后循环内部用if确定循环结束条件(找到了)——break 和循环跳出条件(找不到)—— return
  3. 链表题,还是手写推导试试比较号。
  4. 寻找距离尾部第K个节点,需要first和second初始都为head,然后second后移K-1位,然后first和second一起移动到second的next为null停止,first即为倒数第K个节点。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值