图解链表反转系列Leetcode

单链表反转两种方法 最近同学介绍了一个lettcode(力扣)OJ给我,个人认为这个网站比母校的oj,杭电oj界面友好很多,题库充足,且支持多种主流语言,很适合闲时刷刷提高算法能力,算法的练习如同内功的修炼,碰到算法问题,经常有一种无力感,只能慢慢总结了。 链表是一种重要的数据结构,因为有递归性质,所以总是难以理解,涉及链表的复杂操作总是感觉一头雾水,看别人的实现代码总是似懂非懂,看完就忘,实际上就是没有理解透彻,特... 阅读详情

前言

链表反转是基础数据结构链表的常见操作之一,链表的反转能够产生其他的拓展题目,以下将以LC206 反转链表、LC24 两两交换链表中的节点、LC25 K个一组翻转链表为例进行分析讲解。

LC 206 反转链表

在这里插入图片描述
对于本题,我们通过以下图解来说明。
首先,以下列链表为例:
在这里插入图片描述
这里我们创建一个节点(为null),使用指针pre指向它(作为当前节点的前驱节点),使用指针cur指向当前节点(此时为head节点),再用一个指针node指向当前节点的后继节点。
对于当前节点cur,我们执行以下操作:

  • 首先记录当前节点cur的后继节点; node = cur.next
  • 其次修改当前节点cur的后继节点为pre; cur.next = pre

对于第一个节点来说,当链表全部反转后,它将是最后一个节点,它的后继节点指向null。此时,我们完成了第一个节点的反转。

在这里插入图片描述
对第一个节点操作完成后,我们对第二个节点进行操作。
此时cur指向节点2,也就是上一次操作中的node节点; cur = node
pre指向节点1,也即上一次操作中的cur节点; pre = cur
对于当前节点cur,我们执行同样的操作:

  • 首先记录当前节点cur的后继节点; node = cur.next
  • 其次修改当前节点cur的后继节点为pre; cur.next = pre

此时我们完成了节点2的反转操作。
在这里插入图片描述
以此类推,此时对节点3进行反转:
在这里插入图片描述
此时对节点4进行反转:
在这里插入图片描述
此时对节点5进行反转:
这里注意在原链表中,节点5是最后一个节点,其后继节点为null,当我们依次操作每个节点,直到当前节点为原链表最后一个节点时,对于当前节点cur,我们执行同样的操作:

  • 首先记录当前节点cur的后继节点; node = cur.next
  • 其次修改当前节点cur的后继节点为pre; cur.next = pre

操作完毕,我们可以通过判断node是否为null决定是否返回反转后的链表。
在这里插入图片描述
通过以上的步骤,我们实现了对普通链表的反转操作,代码如下

public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while(cur != null){
            ListNode node = cur.next;
            cur.next = pre;
            if(node == null){
                return cur;
            }
            pre = cur;
            cur = node;
        }
        return cur; 
    }

LC 24 两两交换链表中的节点

在这里插入图片描述
本题是链表反转的拓展版,在简单的链表反转中,我们只需要反转一个链表即可。而在本题中,我们相当于需要反转length / 2个短的链表,每个短链表含有两个节点。(length是链表的长度)

接下来,我们继续进行图解:(依然以上述链表为例)
首先我们对第一个短链表1,2进行反转。同样的,定义一个节点-1,使用指针pre指向它(这里我们可以看到与LC206的区别,LC206的初始pre指向null,因为反转后的链表只有一个,最后一个节点的后继一定为null;而本题的pre指向一个初始化的节点,这是因为对于分段链表,每一段的pre应指向前一段的最后一个节点,而该节点为非空节点),使用指针cur指向当前节点(这里为head节点),使用指针node存储当前节点的后继节点。
在这里插入图片描述
对第一个短链表进行反转,反转后的短链表应为2,1。对当前节点1操作完毕,下一次将对节点3进行操作,那么显而易见的,当前节点cur的后继节点应为操作节点3。而pre节点的后继节点应为反转后短链表的头节点2。
对于当前节点cur执行以下操作:

  • 首先记录当前节点的后继节点; node = cur.next
  • 其次令当前节点的后继节点为node的后继节点; cur.next = node.next
  • 然后令node节点的后继节点为当前节点; node.next = cur
  • 最后令pre节点的后继节点为node节点; pre.next = node;

在这里插入图片描述
操作完毕,得到链表为:
在这里插入图片描述
第一段小的链表反转完毕,即将操作第二段链表,cur指针指向节点3,也即上一步中的cur.next,pre指针指向节点1,也即上一步中node节点的后继节点。
在这里插入图片描述
对第一二短链表进行反转,反转后的短链表应为4,3。对当前节点3操作完毕,下一次将对节点5进行操作,当前节点cur的后继节点应为操作节点5。而pre节点的后继节点应为反转后短链表的头节点4。
对于当前节点cur执行以下操作:

  • 首先记录当前节点的后继节点; node = cur.next
  • 其次令当前节点的后继节点为node的后继节点; cur.next = node.next
  • 然后令node节点的后继节点为当前节点; node.next = cur
  • 最后令pre节点的后继节点为node节点; pre.next = node;

在这里插入图片描述
操作完毕,得到链表为:
在这里插入图片描述
第二段小的链表反转完毕,即将操作第三段链表,cur指针指向节点5,也即上一步中的cur.next,pre指针指向节点3,也即上一步中node节点的后继节点。在第三段短链表中,我们可以看到,该段链表只有一个节点,我们将该段短链表视为5, null。该段链表不需要反转,可以得到链表遍历到最后的出口为cur.next为null。
在这里插入图片描述
通过以上的步骤,我们实现了对两两节点的反转操作,代码如下

public ListNode swapPairs(ListNode head) {
        if (head == null || head.next == null){
            return head;
        }
        ListNode cur = head;
        ListNode pre = new ListNode(-1);
        pre.next = cur;
        ListNode res = head.next;
        while(cur != null && cur.next != null){
            ListNode node = cur.next;
            cur.next = node.next;
            node.next = cur;
            pre.next = node;
            cur = cur.next;
            pre = node.next;
        }
        return res; 
    }

LC25 K个一组翻转链表

在这里插入图片描述
本题是前两道题的综合版,前一道题目两两反转,意味着反转多组短链表,每个链表的长度为2;本题则是反转多组链表,每个链表的长度为k(简单链表反转可以看作反转多组链表,每个链表的长度为1)。自然的,我们的思路为,对于每一组短链表,使用反转简单链表的函数reverse来进行翻转,翻转后将多段短链表连接起来。这里的重点问题是: 如何连接已翻转短链表和未翻转链表?
回顾之前的两道题目,我们定义了指针cur, pre来记录操作节点与操作节点的前驱节点,这里我们同样定义cur和pre,pre指向新创建的节点-1。

在第一个题目中,我们可以看到,cur节点与pre节点的距离为1;且遍历每一个节点时,pre与cur都向右移动一个距离;(pre指向当前短链表的末尾,cur指向下一个短链表的头部)
在这里插入图片描述
在这里插入图片描述
在第二个题目中,我们可以看到,cur节点与pre节点的距离同样为1;而遍历每一个节点时,pre与cur都向右移动两个距离;(pre指向当前短链表的末尾,cur指向下一个短链表的头部)在这里插入图片描述
在这里插入图片描述

那么当短链表长度为k时,cur节点与pre节点的距离为1;遍历每一个节点时,pre与cur都向右移动k个距离,pre指向当前短链表的末尾,cur指向下一个短链表的头部,从而完成k个一组链表的翻转。(这里我们使用pHead记录当前短链表的头节点,nextPre记录下一个短链表的前驱节点,也即当前列表操作后的末尾节点,nextPHead记录下一个短链表的头节点)
顺着这个思路,我们以下列链表为例,令k=3, 图解其翻转过程:
在这里插入图片描述
首先,我们创建新节点-1,指针pre指向节点-1。初始化pHead和nextPre为头节点。对第一段短链表进行操作:

  • 首先遍历第一段链表,找到nextPHead;

在这里插入图片描述

  • 其次对第一段链表进行翻转;
  • 令该段链表的前驱节点pre的后继指向反转后链表的头。 pre.next = reverse(pHead, k)

在这里插入图片描述
得到链表为:
在这里插入图片描述

对第一段链表操作完毕,接下来操作第二段链表。当前段链表的初始头节点pHead为节点4,也即上一次操作中的nextPHead节点;当前端链表的前驱节点pre为节点1,也即上一次操作中的nextPre节点。对于下一段链表,其前驱节点nextPre为本段链表的头节点4,遍历第二段链表,找到nextPHead。
在这里插入图片描述
同样地,

  • 对第二段链表进行翻转;
  • 令该段链表的前驱节点pre的后继指向反转后链表的头。 pre.next = reverse(pHead, k)

在这里插入图片描述
得到链表为:
在这里插入图片描述
对第二段链表操作完毕,操作第三段链表:
在这里插入图片描述
第三段链表长度不足k=3, 所以直接令前驱节点pre的后继节点为当前段链表的头pHead,无需翻转操作。
在这里插入图片描述
通过以上的步骤,我们实现了对K个一组链表的翻转操作,代码如下

public ListNode reverseKGroup(ListNode head, int k) {
        int count = 0;
        ListNode pre = new ListNode(-1);
        pre.next = head;
        ListNode res = pre;
        ListNode pHead = head;
        ListNode nextPHead = head;
        ListNode nextPre = head;
        int len = length(head);
        while(count + k <= len){
            for(int i = 0; i < k; i++){
                count++;
                nextPHead = nextPHead.next;
            }
            
            ListNode partHead = reverse(pHead, k);
            pre.next = partHead;
            pre = nextPre;
            nextPre = nextPHead;
            pHead = nextPHead;   
        }
        if(pHead != null){
            pre.next = pHead;
        }
        return res.next;    
    }

    public ListNode reverse(ListNode head, int k){
        // return the head of the reverse list
        ListNode pre = null;
        ListNode cur = head;
        int count = 0;
        while(count < k){
            ListNode node = cur.next;
            cur.next = pre;
            pre = cur;
            if(count == k - 1){
                return cur;
            }
            cur = node;
            count++;

        }
        return cur;
    }

    public int length(ListNode head){
        if(head == null){
            return 0;
        }
        int len = 0;
        while(head != null){
            len++;
            head = head.next;
        }
        return len;
    }

总结

以上题目之间存在层层递进关系,逐步分析,能够加深对链表反转的理解。

【实战】ACM 选手图解 LeetCode 反转链表 图解 LeetCode 206:反转链表 阅读详情

相关推荐

别再手动上传了!用宝塔面板的‘Let‘s Encrypt’免费SSL证书,3分钟自动续期

本文详细介绍了如何利用宝塔面板的‘Let‘s Encrypt’功能实现SSL证书的自动申请和续期,3分钟完成配置即可永久免费使用。通过对比不同SSL证书方案,突出Let's Encrypt的免费、自动续期和高安全性优势,特别适合个人博客和中小企业官网。

weixin_30415113的博客 150

图解:单链表反转的三种方式!

当我们在聊到链表反转的时候,一定说的都是单链表,双链表本身就具有前驱指针 Prev 和后续指针 next,无需进行翻转。 单链表反转,反转后的效果如下: 看起来很简单,只需要将单链表所有结点的 next 指向,指向它的前驱节点即可。引入一个栈结构,就可以实现。 栈实现的链表反转 在原本链表的数据结构之外,引入一个栈(数组也可),将单链表循环遍历,将所有结点入栈,最后再从栈中循环出栈,记住出栈的...

Android 开发架构 4087

系统安装、qt配置、安装pcie驱动

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 安装Linux系统指定:ununtu20.04并配置相关软件环境 前言 提示:这里可以添加本文要记录的大概内容: ununtu20.04、Qt 5.9.0、pcie驱动 提示:以下是本篇文章正文内容,下面案例可供参考 一、安装系统 制作系统盘(win10),在开机时按相应键进入BIOS,(华硕需要先改配置启动->CSM->开启->第一个选项选第一个或第二个),等待即可 进入后按照https://www.sysgeek.

weixin_44832804的博客 2206

图解反转链表的4种方法

NO.1 剑指 Offer 24. 反转链表 (简单) 定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。 示例: 输入: 1->2->3->4->5->NULL 输出: 5->4->3->2->1->NULL 限制: 0 <= 节点个数 <= 5000 链接:https://leetcode-cn.com/problems/fan-zhuan-lian-biao-lcof/ 方法一: 遍历原链表,把“当前结点

IAMLSL的博客 1768

【STM32】基于STM32F103C8T6实现步进电机精准调速控制

本文详细介绍了如何使用STM32F103C8T6微控制器实现步进电机的精准调速控制。通过利用其内置定时器生成PWM脉冲,替代低效的延时方法,并结合TB6600驱动器进行硬件连接,可实现平滑、高效的电机速度控制。文章提供了基于HAL库的代码实战,包括速度与方向设置函数,并探讨了加减速规划等高级应用,帮助开发者彻底掌握步进电机驱动技术。

weixin_29169899的博客 486

Gemini国内合规接入指南:API身份链构建与镜像站选型

生成式AI服务接入本质是服务可用性工程,而非单纯网络连通问题。理解大模型API调用原理,关键在于掌握身份认证、权限控制与数据流向三大技术要素。Gemini作为主流多模态模型,其国内可用路径已从‘模拟访问’转向‘能力映射’——聚焦文本生成等核心能力的稳定调用。通过构建七步Google Cloud身份链(含+86实名、国际信用卡核验、Service Account最小权限配置),可实现99.2%高成功率的合规API接入;而教育型、企业型、开发者型三类镜像站则提供差异化过渡方案,均需满足端到端加密、境内CDN托管

weixin_29046035的博客 436

LeetCode 第24题两两交换链表中的节点swapPairs

LeetCode 第24题两两交换链表中的节点swapPairs

weixin_41221502的博客 491

元数据管理:DataHub和OpenMetadata对比分析

DataHub和OpenMetadata都试图解决数据编目,搜索,发现,治理和质量方面的相同问题。这两种工具都是出于为需要支持大量数据源、团队和用例的大型组织解决这些问题而诞生的。尽管这些工具在发布历史和成熟度方面略有不同,但它们的功能存在显着重叠。

weixin_38030820的博客 6634

反转链表(递归法)图文详解

通过“先深入后返回”的策略,首先会一直递归调用自身,直到到达链表的尾部,并在递归的过程中改变节点之间的指向来实现链表的反转。具体步骤是先递归地反转子链表,然后将当前节点的下一个节点的指针指向当前节点,并将当前节点的指针指向空。具体步骤是使用三个指针分别指向当前节点、前一个节点和下一个节点,然后在遍历过程中不断更新这三个指针的指向,直到遍历到链表末尾。,意思 4 这个结点指向空结点,不再指向任何结点了,当然包括 5 这个结点。的知识去理解,搞清楚到底函数调用时,原本的参数值是什么。

记录学习与成长! 1776

AI 算力基础设施深度系列(一):从容器到 Kubernetes——算力底座的诞生

1. 容器 = Namespace(视图隔离) + Cgroup(资源限制) + Union FS(镜像分层)└── 不是虚拟机!共享内核,接近零开销2. K8S 三大设计哲学:└── 声明式 API + 控制循环 + 可扩展架构3. K8S 架构:└── 控制面 (API Server / etcd / Scheduler / Controller Manager)

warm3snow的博客 534

国密USB Key开发实战:SKF库调用全流程解析(附代码示例)

本文详细解析了国密USB Key开发中SKF库的调用全流程,涵盖从设备枚举、应用容器遍历到数字签名与验证的核心步骤。通过实战代码示例,深入探讨了SKF库的层次化模型、SM2签名实现细节以及纯软件验签方案,为开发电子签章、安全登录等合规应用提供了一套完整的调用开发指南。

oo7890的博客 526

Solution001两个一组翻转链表

给你一个链表,让你两个两个的将其翻转! 这题其实就是K个一组翻转链表的特例,这里想写一下的目的是,虽然常规做法也是递归,那么我可不可以完全使用递归的方式做一下 方法一:常规做法,先翻转K个链表,再递归 public static ListNode func2(ListNode head){ if (head==null ||head.next==null) return head; ListNode tail = head; for (int i=1;i&.

Oblak_ZY的博客 804

10、智慧变电站 - 加载vue大屏元素(整体效果)

这一篇文章非常简单,但是也非常出效果阅读前面几篇文章,都可以看到有顶部、左侧、右侧的面板,主要我不会录gif图片,大屏元素面板还有一些动态加载的效果。 vue的transition标签 Vue 提供了 transition 的封装组件,可以给任何元素和组件添加进入/离开过渡;在进入/离开的过渡中,会有 6 个 class 切换:v-enter 、v-enter-active 、v-enter-to 、v-leave 、v-leave-active 、v-leave-to。我们正好使用这个特性来达到面板进入

github_39988036的博客 1040

LeetCode反转链表java_Leetcode 反转链表系列 图解详细过程

对于一个程序猿来说,数据结构和算法的重要性就不用我多说了吧,算法题已然成了现在大厂笔试面试的重头戏,废话少说,Leetcode 刷起来呀。说起刷 Leetcode,我建议你按 tag 刷,不然只能像无头苍蝇,东一榔头西一棒槌,最后事倍功半 (过来人的惨痛经历)。最近正好在刷 Leetcode 上的链表题,也碰到了一些颇具代表性的题型,正好做个记录,也分享给有需要的小伙伴。对链表不太熟悉的小伙伴碰到...

weixin_33444829的博客 580

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

Leetcode 反转链表系列 图解详细过程

对于一个程序猿来说,数据结构和算法的重要性就不用我多说了吧,算法题已然成了现在大厂笔试面试的重头戏,废话少说,Leetcode 刷起来呀。说起刷 Leetcode,我建议你按 tag 刷,不然只能像无头苍蝇,东一榔头西一棒槌,最后事倍功半 (过来人的惨痛经历)。最近正好在刷 Leetcode 上的链表题,也碰到了一些颇具代表性的题型,正好做个记录,也分享给有需要的小伙伴。 对链表不太熟悉的小伙伴碰...

IamHYN的博客 624

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

单链表反转,我们从递归说起,图解带你彻底搞懂

单链表反转,我们从递归说起,图解带你彻底搞懂....递归和迭代,看完图解和动画,豁然开朗!

iqqcode 4004

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

【LeetCode训练营】反转链表 移除链表元素 详细图解 203,206

请你反转链表,并返回反转后的链表。,请你删除链表中所有满足。列表中的节点数目在范围。给你一个链表的头节点。

陈大大陈的博客 2248

看一遍就理解,图解单链表反转

前言反转链表是程序员必备的基本素养,经常在面试、笔试的过程中出现。一直觉得反转链表实现代码不是很好理解,决定搬leetcode那道经典反转链表题出来,用十多张图去解析它,希望加深大家对链...

weiwenhou的博客 1640

图解链表反转的过程 -- leetCode 题号:206

这里写自定义目录标题图解链表反转的过程 -- leetCode 题号:206概述题目描述官方答案图解过程第一次迭代:第二次迭代总结 图解链表反转的过程 – leetCode 题号:206 概述 本人算法小白,在遇到单链表反转的这道题目的时候,很是不理解为什么这么写,经过画图一步一步的走,可算是理解这个整体的过程了。 题目描述 题目描述:反转一个单链表。 示例: 输入: 1->2-&gt...

微信公众号《后端学长》 313

Leetcode 102 反转链表

反转链表的核心是「先保存下一个节点,再反转当前指针,最后移动双指针」,顺序绝不能乱;循环条件只需要cur!= nullptr,不用加cur->next!= nullptr,否则最后一个节点处理不到;期末阶段不用追求「算法感悟」,先把这道题的代码背熟、步骤记牢,能稳稳写出正确代码拿分就够了。你已经在坚持打卡了,这就比很多人强!最难的日子一定会过去,先把这道基础题吃透,一步一个脚印,过线肯定没问题~链表的指针操作里,「修改地址」和「访问地址」是互斥的—— 你一旦修改了cur->next。

im_AMBER的博客 1058

【LeetCode题目详解】(二)206.反转链表、876.链表的中间结点

【LeetCode题目详解】(二)206.反转链表、876.链表的中间结点

青色_忘川的博客 1168

力扣 反转链表(图解)

力扣 反转链表(图解)

m0_62750441的博客 581

LeetCode反转链表图解

LeetCode206:反转链表(Easy) 题目 图解 代码详解: class Solution{ private ListNode reverseNodeList(ListNode head){ //1.定义三个节点,分别是pre,cur,nex ListNode pre = null; ListNode cur = head; ListNode nex = null; //2.链表进行反转,当cur为null停止循环 while(cur != null){

保持学习 1154

【力扣-206】反转链表

🖊作者 : Djx_hmbb📘专栏 : 数据结构😆今日分享 :----------“覆蕉寻鹿”:有的人把假的当成真的,而又有人把明明是真的事情当成假的,前者可以说是“黄粱美梦”,后面这种就是“覆蕉寻鹿”。以前有个樵夫打死了一头野鹿,因为一时带不回家,怕被其他人发现,就先用芭蕉叶把牠覆盖起来;后来樵夫去找鹿,忘记了所藏的地方,怎么也找不到,最后以为是自己做了一场梦。所以用“覆蕉寻鹿”来比喻把真实的事情看作梦幻的情况,也可用“覆鹿寻蕉”,都是一个意思。------谢一。

Djx_hmbb的博客 569
上一篇: 无人机使能的边缘计算优化问题
下一篇: 八股打卡(一)
code120302
博客等级 码龄7年 195粉丝 38原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值