快慢指针解决单链表三大问题(Java版)

文章目录

一、快慢指针解决单链表中间值问题

思路分析:

        可以利用两个指针,分别从链表头部遍历链表,一个每次走一个节点(slow),一个每次走两个节点(fast)。这样,当链表节点有奇数个的时候,当快指针走到NULL前面一个节点的时候,此时,慢指针刚好指向链表的中间节点。例如(1,2,3,4,5),慢指针刚好在3这个位置上。当链表节点有偶数个的时候,当快指针走到NULL的时候,此时,慢指针刚好指向链表的中间节点。例如(1,2,3,4,5,6),慢指针刚好在4这个位置上。

代码展示如下:

/* 快慢指针解决链表中点问题 (一道leetCode算法题)*/
class Solution {
    public ListNode middleNode(ListNode head) {
     ListNode fast = head, slow = head;
    //注意:必须要保证fast != null 并且 fast.next != null
     while(fast != null && fast.next != null){
         fast = fast.next.next;
         slow = slow.next;
     }
     return slow;
    }
}


二、快慢指针解决单链表有无环问题

思路分析:

        设置两个指针,一快一慢(快的每次移动的步数是慢的二倍),在这个过程中,如果有环,快指针先进入环,慢指针后续也会进入环,当快慢指针相遇时,即slow == fast(判断条件) ,有环,其实就是快指针绕环转两周,慢指针则转一周,即快指针多走的距离等于环长。如果没有环,快慢指针就不可能相遇,快指针随后移动到末尾null,而慢指针移动到该链表的中间节点位置。

代码展示如下:

package linear;

/**
 * 快慢指针--有无环问题
 */
public class CircleListCheckTest {
    public static void main(String[] args) {
        //创建结点
        Node<String> first = new Node<>("aa", null);
        Node<String> second = 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 = second;
        second.next = three;
        three.next = four;
        four.next = five;
        five.next = six;
        six.next = seven;
        //产生环
        seven.next = three;
        //判断链表是否有环
        boolean circle = isCircle(first);
        System.out.println("first链表中是否有环:" + circle);
    }

    /**
     * @param first 链表首结点
     * @return 链表有环 true 无环 false
     */
    private static boolean isCircle(Node<String> first) {
        //定义两个指针
        Node<String> fast = first;
        Node<String> slow = first;
        //使用两个指针遍历链表,当快指针指向的结点没有下一个结点了,结束循环
        //当快指针指向的和慢指针相遇时,则证明有环 否则无环
            //核心代码块
        while (fast.next != null) {
            fast = fast.next.next;
            slow = slow.next;
            if (fast.equals(slow)) {
                return true;
            }
        }
        return false;
    }

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

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

三、快慢指针解决单链表环入口问题

思路分析:

        要解决环入口,就必须先判断有无环,若有环,则根据先前说到的快慢指针相遇的时候,再重新设立一个与慢指针同速率的一个临时指针(temp)指向头节点,然后当慢指针和临时指针相遇时,该点就是环入口。

代码展示如下:

package linear;

/**
 * 快慢指针--环入口问题
 */
public class CircleListInTest {
    public static void main(String[] args) {
        //创建结点
        Node<String> first = new Node<>("aa", null);
        Node<String> second = 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 = second;
        second.next = three;
        three.next = four;
        four.next = five;
        five.next = six;
        six.next = seven;
        //产生环
        seven.next = three;
        //查找环的入口结点
        Node entrance = getEntrance(first);
        System.out.println("first链表的环入口结点元素为:" + entrance.item);
    }

    /**
     * @param first 链表首结点
     * @return 环入口结点元素
     */
    private static Node getEntrance(Node<String> first) {
        //定义两个指针,和临时指针
        Node<String> fast = first;
        Node<String> slow = first;
        Node<String> temp = null;
        //使用两个指针遍历链表,当快指针指向的结点没有下一个结点了,结束循环
        //当快指针指向的和慢指针相遇时,则证明有环 否则无环
            //核心代码块
        while (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)) {
                    break;
                }
            }
        }
        return temp;
    }

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值