0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

快慢指针的常见算法介绍

jf_78858299 来源:labuladong 作者:labuladong 2023-04-19 10:57 次阅读

我认为双指针技巧还可以分为两类,一类是「快慢指针」,一类是「左右指针」。前者解决主要解决链表中的问题,比如典型的判定链表中是否包含环;后者主要解决数组(或者字符串)中的问题,比如二分查找。

一、快慢指针的常见算法

快慢指针一般都初始化指向链表的头结点 head,前进时快指针 fast 在前,慢指针 slow 在后,巧妙解决一些链表中的问题。

1 、判定链表中是否含有环

这应该属于链表最基本的操作了,如果读者已经知道这个技巧,可以跳过。

单链表的特点是每个节点只知道下一个节点,所以一个指针的话无法判断链表中是否含有环的。

如果链表中不含环,那么这个指针最终会遇到空指针 null 表示链表到头了,这还好说,可以判断该链表不含环。

boolean hasCycle(ListNode head) {
    while (head != null)
        head = head.next;
    return false;
}

但是如果链表中含有环,那么这个指针就会陷入死循环,因为环形数组中没有 null 指针作为尾部节点。

经典解法就是用两个指针,一个每次前进两步,一个每次前进一步。如果不含有环,跑得快的那个指针最终会遇到 null,说明链表不含环;如果含有环,快指针最终会超慢指针一圈,和慢指针相遇,说明链表含有环。

图片

2 、已知链表中含有环,返回这个环的起始位置

图片

这个问题其实不困难,有点类似脑筋急转弯,先直接看代码:


图片

可以看到,当快慢指针相遇时,让其中任一个指针重新指向头节点,然后让它俩以相同速度前进,再次相遇时所在的节点位置就是环开始的位置。这是为什么呢?

第一次相遇时,假设慢指针 slow 走了 k 步,那么快指针 fast 一定走了 2k 步,也就是说比 slow 多走了 k 步(也就是环的长度)。

图片

设相遇点距环的起点的距离为 m,那么环的起点距头结点 head 的距离为 k - m,也就是说如果从 head 前进 k - m 步就能到达环起点。

巧的是,如果从相遇点继续前进 k - m 步,也恰好到达环起点。

图片

所以,只要我们把快慢指针中的任一个重新指向 head,然后两个指针同速前进,k - m 步后就会相遇,相遇之处就是环的起点了。

3 、寻找链表的中点

类似上面的思路,我们还可以让快指针一次前进两步,慢指针一次前进一步,当快指针到达链表尽头时,慢指针就处于链表的中间位置。

ListNode slow, fast;
slow = fast = head;
while (fast != null && fast.next != null) {
    fast = fast.next.next;
    slow = slow.next;
}
// slow 就在中间位置
return slow;

当链表的长度是奇数时,slow 恰巧停在中点位置;如果长度是偶数,slow 最终的位置是中间偏右:

图片

寻找链表中点的一个重要作用是对链表进行归并排序。

回想数组的归并排序:求中点索引递归地把数组二分,最后合并两个有序数组。对于链表,合并两个有序链表是很简单的,难点就在于二分。

但是现在你学会了找到链表的中点,就能实现链表的二分了。关于归并排序的具体内容本文就不具体展开了。

4 、寻找链表的倒数第 k 个元素

我们的思路还是使用快慢指针,让快指针先走 k 步,然后快慢指针开始同速前进。这样当快指针走到链表末尾 null 时,慢指针所在的位置就是倒数第 k 个链表节点(为了简化,假设 k 不会超过链表长度):

ListNode slow, fast;
slow = fast = head;
while (k-- > 0) 
    fast = fast.next;

while (fast != null) {
    slow = slow.next;
    fast = fast.next;
}
return slow;

二、左右指针的常用算法

左右指针在数组中实际是指两个索引值,一般初始化为 left = 0, right = nums.length - 1 。

1 、二分查找

前文 [二分查找算法详解] 有详细讲解,这里只写最简单的二分算法,旨在突出它的双指针特性:

图片

2 、两数之和

直接看一道 LeetCode 题目吧:

图片

只要数组有序,就应该想到双指针技巧。这道题的解法有点类似二分查找,通过调节 left 和 right 可以调整 sum 的大小:

图片

3 、反转数组

void reverse(int[] nums) {
    int left = 0;
    int right = nums.length - 1;
    while (left < right) {
        // swap(nums[left], nums[right])
        int temp = nums[left];
        nums[left] = nums[right];
        nums[right] = temp;
        left++; right--;
    }
}

4 、滑动窗口算法

这也许是双指针技巧的最高境界了,如果掌握了此算法,可以解决一大类子字符串匹配的问题,不过「滑动窗口」算法比上述的这些算法稍微复杂些。

幸运的是,这类算法是有框架模板的,下篇文章就准备讲解「滑动窗口」算法模板,帮大家秒杀几道 LeetCode 子串匹配的问题。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 算法
    +关注

    关注

    23

    文章

    4455

    浏览量

    90756
  • 初始化
    +关注

    关注

    0

    文章

    48

    浏览量

    11629
  • 单链表
    +关注

    关注

    0

    文章

    13

    浏览量

    6882
收藏 人收藏

    评论

    相关推荐

    浅析函数指针指针函数及其应用

    什么是指针?相信大家对这个问题其实并不陌生,对指针的概念也不会很模糊,在这里我也大概介绍一下。
    发表于 03-08 13:17 134次阅读

    函数指针指针函数的概念

    不少朋友会混淆“函数指针”和“指针函数”这两个概念,本文详细介绍一下。
    发表于 03-09 10:49 919次阅读

    几种常见的滤波算法

    **几种常见的滤波算法**限幅滤波算法(程序判断滤波算法)顾名思义,就是单纯用程序来处理输入数据In_data,通过对相邻两次数据取误差的绝对值 |error|,通过经验判断两次In_
    发表于 01-11 06:37

    过程间指针分析算法的改进

    指针分析对于使用C语言编制程序的数据流分析有着重要的意义。该文介绍指针问题的复杂度、指针分析算法的分类以及
    发表于 04-02 09:05 9次下载

    C语言入门教程-指针常见错误

    指针常见错误 错误 1:未初始化的指针一个最易犯的指针错误是试图引用未初始化(因而指向的是无效地址)的指针。例如: int*p; *
    发表于 07-29 11:47 976次阅读

    C语言中指针介绍非常详细

    C语言中指针介绍非常详细 C语言中指针介绍非常详细
    发表于 12-25 10:39 57次下载

    C语言指针函数和函数指针详细介绍

    C语言指针函数和函数指针详细介绍。。。。。。。
    发表于 03-04 15:27 5次下载

    再再论指针

    关于指针的几个关键概念及常见问题。
    发表于 04-05 15:53 0次下载

    c语言函数指针定义,指针函数和函数指针的区别

     往往,我们一提到指针函数和函数指针的时候,就有很多人弄不懂。下面就由小编详细为大家介绍C语言中函数指针指针函数和函数
    发表于 11-16 15:18 3408次阅读

    C指针编程之道PDF电子书免费下载

    《C指针编程之道》由孔浩、张华杰、陈猛编著,是一本帮助程序员提高编程素养的图书,书中结合开发人员多年的编程经验和感悟,介绍指针在数组中的应用、在函数中的应用、指向指针
    发表于 04-01 08:00 22次下载
    C<b class='flag-5'>指针</b>编程之道PDF电子书免费下载

    理解函数指针、函数指针数组、函数指针数组的指针

    理解函数指针、函数指针数组、函数指针数组的指针
    的头像 发表于 06-29 15:38 1.4w次阅读
    理解函数<b class='flag-5'>指针</b>、函数<b class='flag-5'>指针</b>数组、函数<b class='flag-5'>指针</b>数组的<b class='flag-5'>指针</b>

    快慢指针、左右指针常见算法

    技巧秒杀 5 道算法题。 其实,鼎鼎有名的「滑动窗口算法」就是一种双指针技巧,我们之前的爆文我写了套框架,把滑动窗口算法变成了默写题就有这么一段: 我把双
    的头像 发表于 11-26 14:09 2293次阅读

    四种常见的图像滤波算法介绍

    滤波算法,并附上源码,包括自适应中值滤波、高斯滤波、双边滤波和导向滤波。 前言 本文介绍四种常见的图像滤波算法,并附上源码。图像滤波是一种非常重要的图像处理技术,现在大火的卷积神经网络
    的头像 发表于 02-15 09:50 9389次阅读

    数组相关的双指针算法

    对于单链表来说,大部分技巧都属于快慢指针,前文 单链表的六大解题套路 都涵盖了,比如链表环判断,倒数第K个链表节点等问题,它们都是通过一个fast快指针和一个slow慢指针配合完成任务
    的头像 发表于 04-28 16:22 1728次阅读

    C语言-一维指针定义与使用

    指针在很多书本上都是当做重点来介绍,作为C语言的灵魂,项目里指针无处不在。 这篇文章介绍指针的基本用法。
    的头像 发表于 08-14 10:02 1085次阅读