龟兔赛跑算法(快慢指针)解决链表问题案例汇总

这几日刷到了很多链表的算法题,发现链表的算法题真的很抽象,基本都不太会做。。。无奈只能看评论和大佬的题解,总算是有了点启发和思路,趁着记忆还未褪却赶紧来记录下来。我发现这些链表的题大佬们都很喜欢用快慢指针来做,所以我特地做了一个汇总,不得不说,快慢指针真的很好用!!

  1. 判断链表是否有环?
    在这里插入图片描述
    本题的思路也是用快慢指针来做的,空间复杂度可以是O(1),常量的空间复杂度真的很高效,如何用快慢指针来做呢?无非就是判断快慢两个指针最后是否会相遇,如果有环的话,快慢两个指针最后肯定会相遇,那么我们只需要在循环里面加一个if判断就好了,返回true,其他的都是返回false。用快慢指针来解决这个问题是我认为最好理解的,就好比龟兔赛跑一样,如果赛道是一个环的话兔子和乌龟最终都会相遇,灵魂就是一个快一个慢!!
    代码如下:
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    //快慢指针解决链表有无环的问题 原理 如果有环的话快慢指针早晚会相遇 又称龟兔赛跑算法
    public boolean hasCycle(ListNode head) {
        ListNode gui;
        ListNode tu;
        gui=tu=head;
        if(head == null || head.next==null){
            return false;
        }   
        while(head != null){
            if(tu == null || tu.next==null){
                return false;
            }
            tu = tu.next.next;//快指针永远比慢指针快一步
            gui = gui.next;
            if(tu == gui){
                return true;
            }
        }
        return false;
    }
}

运行效率:
在这里插入图片描述
2. 回文链表
在这里插入图片描述
本题解题思路依旧是用了快慢指针,回文数即前后顺序都一样的一串数,只不过这里是链表,如果是字符串或者是数组的话会很容易解决,但是链表的话需要进行一些额外的操作,比如反转链表等,下一题我会顺便贴一个反转链表的题。现在我们先来看这个题目,由题目可知,我们只需要用两个指针,一个快,一个慢,当快指针到达链表尾部的时候,慢指针刚好到达链表的中间,然后我们将前部分的链表进行反转链表然后对比前后两端链表是否相等就可以了,思路一旦清晰了,实现起来就快得多了。额外说一下本题的前半部分反转链表是在遍历的时候就顺便反转了,而不是到最后整体翻转,
代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    //本题用快慢指针来求解
    public boolean isPalindrome(ListNode head) {
        ListNode pre = null;//预先指针
        ListNode slow = head;//慢指针
        ListNode fast = head;//快指针
        while(fast != null && fast.next != null){
            ListNode temp = slow.next;
            if(pre != null) {
                slow.next = pre;
            }
            pre = slow;
            fast = fast.next.next;
            slow = temp;
        }
        if(fast != null) slow = slow.next;
        while(slow != null){
            if(slow.val != pre.val) return false;
            slow = slow.next;
            pre = pre.next;
        }
        return true;
    }
}

结果效率:
在这里插入图片描述
3. 反转链表
在这里插入图片描述
这道题目很简单,并不是用快慢指针来解决的,而是简单的运用指针的变化来实现的反转,迭代链表,让当前节点的下一个节点都指向它本身的上一个节点,即实现了局部反转,节点的位置没有改变,改变的仅仅是next指针指向的方向
代码实现:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;//表示当前节点的前一个节点
        ListNode cur = head;//表示当前节点

        //我们要实现反转只需要将当前节点的下一个节点指向当前节点的前一个节点即可 
        //如此反复到最后一个节点
        while(cur != null){
            ListNode t = cur.next;
            cur.next = pre;//当前节点的下一个节点指向当前节点的上一个节点 实现局部反转
            pre = cur;
            cur = t;
        }
        return pre;
    }
}

结果效率:
在这里插入图片描述
4. 合并两个有序链表
这个题目用的是递归,递归很迷,每次看代码的时候思路都很清晰感觉很简单,但是每次一写都觉得很难。。。
在这里插入图片描述
思路:因为给定的两个链表是有序的,这样就好做多了。用递归的话就要有结束条件l1和l2等于null的时候就会返回响应的l。
然后我们通过三目运算符来判断两个链表的值谁大谁小,小的那个节点的下一个节点指向一个递归,递归带的参数是本节点的next和一个三目运算符,用作判断谁大谁小
执行效率:
在这里插入图片描述

参考题解:https://leetcode-cn.com/problems/merge-two-sorted-lists/solution/yi-kan-jiu-hui-yi-xie-jiu-fei-xiang-jie-di-gui-by-/

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java中,使用快慢指针(也称为龟兔赛跑法)是常见的判断链表是否有环的方法。这种方法基于两个指针,一个每次移动一个节点,另一个每次移动两个节点。如果链表中有环,那么快指针最终会追上慢指针;如果没有环,快指针会先到达链表尾部。 下面是基本的实现步骤: 1. 初始化两个指针:`slow`(慢指针)和`fast`(快指针),分别指向链表的头节点。 2. 指针遍历:如果链表不为空,循环执行以下操作: a. `slow`向前移动一步(`slow.next`)。 b. `fast`向前移动两步(`fast.next.next`)。 3. 判断环的存在:如果`fast`指针在某次迭代中到达了`null`,说明链表没有环,因为快指针走过的距离是慢指针的两倍,如果链表长度为偶数,快指针应该在链表末尾找到慢指针,如果奇数,则会先到尾部再回环,不会追上。如果`fast`始终不为`null`,且与`slow`相遇(它们都指向同一个节点),那么链表中存在环。 下面是伪代码形式的实现: ```java public boolean hasCycle(ListNode head) { ListNode slow = head; ListNode fast = head; // 如果链表为空或只有一个节点,不存在环 if (head == null || head.next == null) { return false; } // 快慢指针开始遍历 while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; // 如果快指针先到末尾,则链表无环 if (fast == null) { return false; } // 如果快慢指针相遇,说明链表有环 if (slow == fast) { return true; } } return false; // 如果没有提前结束循环,说明链表无环 } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值