单链表-快慢指针

单链表-快慢指针

​ 快慢指针指的是定义两个指针,这两个指针的移动速度一快一慢,通常快指针的移动速度为慢指针的2倍。以此来制造出自己想要的差值,这个差值可以帮我们找到链表上相应的结点。

1. 中间值问题

原理:利用快慢指针,我们可将一个链表看成是一个跑道,假设a的速度是b的两倍,那么当a跑完全程后,b刚好跑完一半,以此来找到中间结点。

在这里插入图片描述

/**
 * 快慢指针求链表中间值
 * 当链表结点为奇数个:如7个结点,那么中间为(7+1)/2 = 4
 * 当链表结点为偶数个:如6个结点,那么中间为(6+2)/2 = 4
 */
public class FastSlowPointer {
    public static void main(String[] args) {
        //声明结点
        Node<String> first = new Node<>("aa", null);
        Node<String> two = new Node<>("bb", null);
        Node<String> three = new Node<>("cc", null);
        Node<String> four = new Node<>("dd", null);
        Node<String> five = new Node<>("ee", null);
        Node<String> six = new Node<>("ff", null);
        Node<String> seven = new Node<>("gg", null);
        //结点链接
        first.next = two;
        two.next = three;
        three.next = four;
        four.next = five;
        five.next = six;
        six.next = seven;

        String mid = getMid(first);
        System.out.println(mid);
    }

    /**
     * 利用快慢指针查找链表中间值。
     * 一般快指针的跳转是慢指针的二倍,快指针到最后结点时候,慢指针正好指着链表中间结点
     * 1. 定义快、慢两个指针,皆指向第一个结点
     * 2. 进入while循环,将快指针运行速度设定为慢指针的2倍
     * @param first :链表第一个结点
     * @return :返回中间结点的数据域
     */
    private static String getMid(Node<String> first) {
        Node<String> slow = first;
        Node<String> fast = first;
        while (fast != null && fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
        }
        return slow.item;
    }

    //定义结点
    private static class Node<T> {
        //结点数据
        private T item;
        //下一个结点
        private Node<T> next;

        public Node(T item, Node<T> next) {
            this.item = item;
            this.next = next;
        }
    }
}

2. 判断单链表是否有环

原理:使用快慢指针的思想 ,将链表比作一条跑道,那么这条跑道就是一条圆环跑道,在一条圆环跑道中 ,两个人有速度差,那么终有快慢指针相遇的时刻,只要相遇就表示有环。

在这里插入图片描述

/**
 * 快慢指针判断是否链表有环
 */
public class FastSlowPointerIsCircle {
    public static void main(String[] args) {
        Node<String> first = new Node<>("aa", null);
        Node<String> two = new Node<>("bb", null);
        Node<String> three = new Node<>("cc", null);
        Node<String> four = new Node<>("dd", null);
        Node<String> five = new Node<>("ee", null);
        Node<String> six = new Node<>("ff", null);
        Node<String> seven = new Node<>("gg", null);
        //结点链接
        first.next = two;
        two.next = three;
        three.next = four;
        four.next = five;
        five.next = six;
        six.next = seven;
        //产生环
        seven.next = three;
        System.out.println(isCircle(first));
    }

    /**
     * 判断是否存在环
     * 方法:因为快指针比慢指针快二倍,如果存在环,则二者肯定会再某一刻指向相同
     * @param first
     * @return
     */
    private static boolean isCircle(Node<String> first){
        //快指针
        Node<String> fast = first;
        //慢指针
        Node<String> slow = first;
        while (fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast.equals(slow)){
                return true;
            }
        }
        return false;
    }

    //定义结点
    private static class Node<T> {
        //结点数据
        private T item;
        //下一个结点
        private Node<T> next;

        public Node(T item, Node<T> next) {
            this.item = item;
            this.next = next;
        }
    }
}

3. 求有环链表入口问题

原理:快慢指针相遇,则证明链表有环,这时重新设定一个新指针指向链表的起点,且步长与慢指针相同都为1,当慢指针与新指针相遇的地方,就是环的入口。

在这里插入图片描述

public class FastSlowPointerIsCircle {
    public static void main(String[] args) {
        Node<String> first = new Node<>("aa", null);
        Node<String> two = new Node<>("bb", null);
        Node<String> three = new Node<>("cc", null);
        Node<String> four = new Node<>("dd", null);
        Node<String> five = new Node<>("ee", null);
        Node<String> six = new Node<>("ff", null);
        Node<String> seven = new Node<>("gg", null);
        //结点链接
        first.next = two;
        two.next = three;
        three.next = four;
        four.next = five;
        five.next = six;
        six.next = seven;
        //产生环
        seven.next = three;
        System.out.println(getEntrance(first).item);
    }

    /**
     * 获得环的入口
     * 当快慢指针相遇时,表示表中有环,这是重新设定一个新的指针指向链表起点,且步长与slow相同为1
     * 当慢指针与新指针相遇的地方就是环的入口。
     * @param first
     * @return
     */
    private static Node<String> getEntrance(Node<String> first){
        //快指针
        Node<String> fast = first;
        //慢指针
        Node<String> slow = first;
        //临时指针·新节点
        Node<String> temp = null;
        while (fast!=null&&fast.next!=null){
            fast = fast.next.next;
            slow = slow.next;
            if (fast.equals(slow)){
                temp = first;
                continue;
            }
            if (temp!=null){
                temp = temp.next;
                if (temp.equals(slow)){
                    return temp;
                }
            }
        }
        return null;
    }

    //定义结点
    private static class Node<T> {
        //结点数据
        private T item;
        //下一个结点
        private Node<T> next;

        public Node(T item, Node<T> next) {
            this.item = item;
            this.next = next;
        }
    }
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值