返回中间节点;返回倒数k节点;判断是否为环形链表(返回入环第一个节点)

今天我们使用典型的快慢指针解决这几个典型问题

一.返回中间节点

问题

给定一个头结点为 head 的非空单链表,返回链表的中间结点。(如果有两个中间结点,则返回第二个中间节点)

思路

这里我们设置两个指针,slow和fast,一个走一步,一个走两步,等fast走完链表,那么slow就在中间节点。
这里比较简单也好想,我就不画图了。一些小细节,我也在代码里解释到了。

代码

public ListNode middleNode(ListNode head) {
        //定义快慢指针
        ListNode fast=head;
        ListNode slow=head;
        //快指针遍历完的的标志
        //这里fast!=null和fast.next!=null,这两个不能换位置哦,防止空指针异常。
        //当fast为null时,就不会判断fast.next了。
        while(fast!=null&&fast.next!=null){
            //走两步
            fast=fast.next.next;
            //走一步
            slow=slow.next;
        }
        return slow;
    }

二.返回倒数k节点

问题

输入一个链表,输出该链表中倒数第k个结点。
(问题简洁,我们也好考虑)

思路

首先依然是两个指针,slow和fast,求倒数第k个,那么我们就让fast先走(k-1)步,之后fast走一步和slow也走一步,等fast走完链表,slow就是所求倒数k个节点;因为返回的是slow,为什么是k-1步,也很好理解,不太理解的可以这样想。如果是求倒数第一个节点,那么slow和fast便应该处于同一个节点上。画图遍历一遍就可以理解了。

代码

public ListNode FindKthToTail(ListNode head,int k) {
        //为空直接结束
        if(head==null){
             return null;
         }
        //求得倒数k不合法那也不行,k大的不合法在下面处理
        if(k<=0){
            return null;    
        }
        //定义快慢指针
        ListNode fast=head;
        ListNode slow=head;
        //让fast先走k-1步
        while((k-1)!=0){
            //这里就是在处理如果k大于链表的长度,那么依然返回null
            if(fast.next!=null){
                fast=fast.next;
                k--;
            }else{
                return null;
            }
        }
        //让slow和fast同时一块走动,当fast到尾部时,结束循环
        while(fast.next!=null){
            fast=fast.next;
            slow=slow.next;
        }
        //返回slow
        return slow;
    }

三.判断是否有环形链表

问题

给定一个链表,判断链表中是否有环。
(如果链表中存在环,则返回 true 。 否则,返回 false 。)
在这里插入图片描述
环一定是存在尾部。

思路

定义一个快慢指针,slow和fast。slow走一步,fast走两步,当存在环的时候,slow和fast因为存在差距,所以在环中一定相遇。当slow==fast,那么就证明存在环;当fast.next ==null,那么证明没有环

代码

public boolean hasCycle(ListNode head) {
        //定义快慢指针
        ListNode fast=head;
        ListNode slow=head;
        //fast走两步,slow走一步
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            //相遇证明存在环
            if(fast==slow){
                break;
            }
        }
        //证明没有环
        if(fast==null || fast.next==null){
            return false;
        }
        return true;
    }

如果要返回其环的第一个节点

问题

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

思路

定义快慢指针,slow和fast,slow走一步,fast走两步,先找到slow和fast在环中的相遇位置;之后重置slow=head,然后继续走,但是这时,slow走一步,fast也走一步,当slow和fast相遇的时候,那么就是环入口的第一个节点。
在这里插入图片描述

代码

 public ListNode detectCycle(ListNode head) {
        //定义快慢指针
        ListNode fast=head;
        ListNode slow=head;
        //fast走两步,slow走一步
        while(fast!=null && fast.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            //相遇存在环
            if(fast==slow){
                break;
            }
        }
        //确保存在环
        if( fast == null || fast.next==null){
            return null;
        }
        //让slow退回到head
        slow=head;
        //这时让slow和fast同时走一步,这个需要理解上面我画的图。
        while(slow!=fast){
            slow=slow.next;
            fast=fast.next;
        }
        return slow;
    }
  • 9
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值