单向链表快慢指针实际应用问题

快慢指针


所谓快慢指针:就是利用两个指针移动速度的不同来实现需求,一般设置两个指针,慢指针每次移动一格,快指针每次移动两格。下面分享利用快慢指针解决中间值、链表环路以及环路入口的问题。

中间值问题


利用快慢指针,当快指针移动到尾部的时候,慢指针所在的位置即为链表的中间位置

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6kvb3O0I-1682338938354)(C:\Users\29973\AppData\Roaming\Typora\typora-user-images\image-20230424100843691.png)]

//实现快慢指针查找中间值
public class FastSlow {

    public static void main(String[] args) {
        //创建结点
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);
        Node<String> eight = new Node<String>("hh", null);

        //完成结点之间的指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;
        seven.next = eight;

        System.out.println("中间值是:"+getMid(first));
    }

    //查找中间值,传入的为头节点
    public static String getMid(Node head){
        //定义两个指针,fast一次移动两步,slow一次移动一步
        Node<String> fast = head;
        Node<String> slow = head;
        //使用两个指针进行遍历,当fast移动到尾部的时候,slow则为中间
        while (fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow.item;
    }
}

单向链表有环问题


在这里插入图片描述

原理:因为快指针始终走比慢指针快,那么如果有环,则一定会相遇,即如果快慢指针指向了同一个节点,证明有环

public class CircleCheck {

    public static void main(String[] args) {
        //创建结点
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);
        Node<String> eight = new Node<String>("hh", null);

        //完成结点之间的指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;

        //创造环
        seven.next = third;

        System.out.println("链表是否有环:"+isCircle(first));
    }

    /**
     * @description 校验链表是否有环
     * @params [head]头节点
     * @returns boolean 返回是否有环
     */
    public static boolean isCircle(Node<String> head){
        //定义快慢指针
        Node<String> fast = head;
        Node<String> slow = head;

        //遍历链表,如果快慢指针指向了同一个节点,那么证明有环
        while (fast!=null && fast.next!=null){
            //变换fast和slow指向
            fast = fast.next.next;
            slow = slow.next;

            if (fast.equals(slow)){
                return true;
            }
        }
        return false;
    }
}

有环链表入口问题


当快慢指针相遇时,我们可以判断到链表中有环,这时重新设定一个新指针指向链表的起点,且步长与慢指针一样为1,则慢指针与“新”指针相遇的地方就是环的入口

public class CircleCheck {

    public static void main(String[] args) {
        //创建结点
        Node<String> first = new Node<String>("aa", null);
        Node<String> second = new Node<String>("bb", null);
        Node<String> third = new Node<String>("cc", null);
        Node<String> fourth = new Node<String>("dd", null);
        Node<String> fifth = new Node<String>("ee", null);
        Node<String> six = new Node<String>("ff", null);
        Node<String> seven = new Node<String>("gg", null);
        Node<String> eight = new Node<String>("hh", null);

        //完成结点之间的指向
        first.next = second;
        second.next = third;
        third.next = fourth;
        fourth.next = fifth;
        fifth.next = six;
        six.next = seven;

        //创造环
        seven.next = third;

        System.out.println("链表环的入口为:"+getEntrance(first).item);
    }

    /**
     * @description 找到有环链表的入口
     * @date 2023/4/24 9:49
     * @params [head] 头节点
     * @returns Node 返回入口的值
     */
    public static Node getEntrance(Node<String> head){
        //定义快慢指针
        Node<String> fast = head;
        Node<String> slow = head;
        Node<String> temp = null;
        //遍历链表,先找到环,随后准备一个临时指针指向链表的首节点
        //继续遍历,当临时指针和慢指针相遇的时候,指向的节点就是环的入口
        while (fast!=null && fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;

            //判断快慢指针是否相遇
            if (fast.equals(slow)){
                temp = head;
                continue;
            }

            //判断慢指针是否和临时指针相遇
            if (temp!=null){
                temp = temp.next;
                if (temp.equals(slow)){
                    break;
                }
            }
        }
        return temp;
    }
}

参考
黑马程序员Java数据结构与java算法全套教程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值