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

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

对链表不太熟悉的小伙伴碰到链表问题可能会觉得无从下手,相比数组,链表确实会更加抽象,也需要一定的空间想象力,特别是一些指针戳来戳去,容易把人搞懵。这个时候你不妨拿出纸笔,画个简单的示意图,这对你解决链表问题非常有帮助。本篇文章将以图解的方式介绍三道链表反转的算法题,在 Leetcode 上分别对应简单、中等和困难的难度级别,算是比较有代表性的题型,对于解决链表问题很有参考意义。

1、 Leetcode 206 题 Reverse Linked List (难度:简单)

题目描述如下:

a29834955ffb?utm_campaign=hugo

反转链表I题目描述

解法一、迭代反转

先来看示意图,以链表1->2->3->4->5为例:

a29834955ffb?utm_campaign=hugo

单链表迭代反转示意图

在遍历链表时,每一次循环只需要做三件事,1. 把当前节点的 next 指针指向其前驱节点;2. 把前驱节点指针指向当前节点;3. 把当前节点指针指向其下一个节点。需要注意的是,我们需要一个变量来暂存当前节点的下一个节点,这里我们用 temp 表示,代码如下

public ListNode reverseList(ListNode head) {

// 前驱节点初始为null

ListNode prev = null;

// 当前节点用cur表示

ListNode cur = head;

// 用temp暂存下一个节点

ListNode temp;

while (cur != null) {

// 获取下一个节点

temp = cur.next;

// 把当前节点的 next 指针指向其前驱节点

cur.next = prev;

// 把前驱节点指针指向当前节点

prev = cur;

// 把当前节点指针指向其下一个节点

cur = temp;

}

// 注意最后返回的是prev

return prev;

}

解法二、递归反转

很多题目用递归都可以写出相当简洁的答案,不过相对于迭代,递归确实没那么好理解。本菜鸡至今也只会用递归解决一些相当基础的题目,比如本题。很多人在面对递归问题时都很容易陷入细节中无法自拔,但是再聪明的脑袋恐怕装不了几层递归栈,所以应该把重点放在子问题和结束条件上。这次先上代码再上图

public ListNode reverseList(ListNode head) {

// 递归终止条件是当前节点为空,或者当前节点的下一个节点为空

// 毫无疑问,在这道题中返回的就是单链表的尾节点

if(head == null || head.next==null) {

return head;

}

// 将当前节点之后的子链表反转任务交给子过程处理,不要陷入细节

// 只需要知道子过程可以完成子链表的反转就够了

ListNode p = reverseList(head.next);

// 经过上面的反转,子链表已经反转完成,接下来要做的就是处理子链表和当前节点的关系

// 下面两步配合示意图理解

head.next.next = head;

// 防止链表循环,需要将head.next置为空

head.next = null;

// 每一层递归函数返回的都是p,也就是初始链表的尾节点

return p;

}

假设链表是 1->2->3->4->5,下面是递归过程示意图。

a29834955ffb?utm_campaign=hugo

单链表递归反转示意图

下面再贴一个 Leetcode 本题讨论区的一个热评,希望可以帮助你理解递归过程。

不妨假设链表为1,2,3,4,5。按照递归,当执行reverseList(5)的时候返回了5这个节点,reverseList(4)中的p就是5这个节点,我们看看reverseList(4)接下来执行完之后,5->next = 4, 4->next = null。这时候返回了p这个节点,也就是链表5->4->null,接下来执行reverseList(3),代码解析为4->next = 3,3->next = null,这个时候p就变成了,5->4->3->null, reverseList(2), reverseList(1)依次类推,p就是:5->4->3->2->1->null。

题目描述如下:

a29834955ffb?utm_campaign=hugo

翻转链表II题目描述

解析:本题,还有下一个要介绍的困难级别的题目,算是一种类型题,它们都是要对链表中特定区间中的节点进行操作。面对这种题目,有固定的套路可以帮你简化解题思路,套路如下:

给链表添加虚拟头节点 dummy,这样就不需要再单独考虑头节点了,可以省去很多麻烦;

找到需要操作的链表区间,区间起始节点用 start 表示,结束节点用 end 表示;

对区间上的链表进行操作;

将操作后的链表重新接回原链表,这里我们需要另外两个变量,前驱节点 prev 和后继节点 successor。

这样,我们就完成了所有操作,返回 dummy.next 即可,示意图如下

a29834955ffb?utm_campaign=hugo

单链表区间反转示意图

然后上代码:

public ListNode reverseBetween(ListNode head, int m, int n) {

// 添加虚拟头节点

ListNode dummy = new ListNode(0);

dummy.next = head;

// 前驱节点

ListNode prev = dummy;

// 反转区间开始节点

ListNode start = head;

// 反转区间结束节点

ListNode end = head;

// 后继节点

ListNode successor;

// 第一个for循环可以找到前驱节点和区间开始节点

for (int i = 1; i < m; i++) {

prev = prev.next;

start = start.next;

end = end.next;

}

// 第二个for循环可以找到区间结束节点

for (int i = m; i < n; i++) {

end = end.next;

}

// 找到后继节点

successor = end.next;

// 至关重要的一步,将反转区间的最后一个节点和原链表断开,否则会造成死循环

end.next = null;

// 将反转后的头节点连在前驱结点后面,这里的 reverseList() 方法直接复用上一题的翻转单链表方法即可

prev.next = reverseList(start);

// 反转后,start变成尾结点,把它和后继结点连接起来

start.next = successor;

return dummy.next;

}

public ListNode reverseList(ListNode head) {

ListNode prev = null;

ListNode cur = head;

ListNode temp;

while (cur != null) {

temp = cur.next;

cur.next = prev;

prev = cur;

cur = temp;

}

return prev;

}

3、Leetcode 25题 K 个一组翻转链表(难度:困难)

题目描述如下:

a29834955ffb?utm_campaign=hugo

K个一组反转链表题目描述.png

解析:本题与上一题有很大的相似之处,都是对区间上的链表进行操作,不同的是本题需要连续对多个区间进行操作,看似无从下手,其实只比上一题多了个循环的过程,过程如下图所示:

a29834955ffb?utm_campaign=hugo

K个一组反转链表示意图

代码如下:

public ListNode reverseKGroup(ListNode head, int k) {

// 添加虚拟头结点

ListNode dummy = new ListNode(0);

dummy.next = head;

ListNode prev = dummy;

ListNode start = head;

ListNode end = head;

ListNode successor;

while (end != null) {

// 循环k次,确定待反转区间

for (int i = 1; i < k && end != null; i++) {

end = end.next;

}

// end节点为空的话说明待反转节点不足k个,直接返回

if (end == null) {

break;

}

successor = end.next;

//至关重要的一步,将待反转链表的最后一个节点和后续链表断开

end.next = null;

// 进行反转链表操作,并将反转后的链表头结点连接在prev之后

// 这里的 reverseList() 方法直接复用第一题的翻转单链表方法即可

prev.next = reverseList(start);

// start在反转后会变成尾结点,将其与successor连接起来

start.next = successor;

// 以下对各变量重新赋值,然后进行下一次循环

prev = start;

start = successor;

end = successor;

}

return dummy.next;

}

public ListNode reverseList(ListNode head) {

ListNode prev = null;

ListNode cur = head;

ListNode temp;

while (cur != null) {

temp = cur.next;

cur.next = prev;

prev = cur;

cur = temp;

}

return prev;

}

4、总结

来来来再总结一下,很多链表题都可以通过添加虚拟头结点来简化解题思路,对于区间操作的情况,可以考虑使用前驱、后继、开始和结束等变量,另外就是要多动笔画画,毕竟眼睛看到的会更加直观。

艾玛终于掰扯完了,这些图真是画得我身心俱疲,就当是做个笔记加深印象吧,也希望可以帮到有需要的小伙伴。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/506390.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

amd插帧技术如何开启_联想ThinkPad笔记本电脑如何开启CPU的虚拟化技术图文教程...

联想ThinkPad笔记本电脑如何开启CPU的虚拟化技术图文教程很多情况下可能我们都需要开启CPU虚拟化技术&#xff0c;例如我们需要打开安卓模拟器&#xff0c;在打开安卓模拟器的时候如果提示您需要CPU虚拟化技术&#xff0c;那么我们需要在主板BIOS设置中进行开启&#xff0c;下面…

没有内存条电脑能开机吗_换内存加固态,老电脑也能快到起飞,附纯国产内存条雷赤测评...

我在公司里用的那台电脑是品牌机&#xff0c;配置有点低&#xff0c;处理器是i3-6100&#xff0c;内存是4GB&#xff0c;硬盘是1TB的机械&#xff0c;这个配置日常办公是没有问题的&#xff0c;但是现在有一些活已经超出了这个配置的能力&#xff0c;加之近期的一些工作还需要在…

嵌入式编程要不要学数据结构_少儿编程要不要学?其实国家早就给出了答案……...

随着人工智能的热度不断攀升&#xff0c;少儿编程越来越火&#xff0c;逐渐成为爸妈们的热门话题。自家的孩子适不适合学习少儿编程&#xff0c;很多专业人士发出了各种不同的声音。这也让很多望子成龙的家长一头雾水&#xff0c;分不清究竟该何去何从&#xff1f;那么&#xf…

nrf52840 gpiote如何配置中断输入_西门子S7-200 SMART PID回路控制,配置PID向导,查看项目组件...

本篇我们继续来学习西门子S7-200 SMART的PID回路控制&#xff0c;首先介绍一下如何配置PID向导。在工具菜单功能区单击PID按钮打开PID回路向导对话框&#xff0c;选择要组态的回路&#xff0c;最多可组态8个回路&#xff0c;这里我们选择回路0。选择回路0在左侧的树视图中单击回…

java 大流量高并发_【BAT面试题】如何应对大流量、高并发??

这是一道BAT大厂的面试题所谓高并发指的是&#xff1a;在同时或极短时间内&#xff0c;有大量的请求到达服务端&#xff0c;每个请求都需要服务端耗费资源进行处理&#xff0c;并做出相应的反馈。常用的高并发处理的思路与手段从服务端视角看高并发服务端处理请求需要耗费服务端…

创建一个storageevent事件_谈谈StorageEvent

编者按&#xff1a;本文作者 刘观宇&#xff0c;360 奇舞团高级前端工程师、技术经理&#xff0c;W3C CSS 工作组成员。纷纷红紫已成尘&#xff0c;布谷声中夏令新。夹路桑麻行不尽&#xff0c;始知身是太平人。 ——宋.陆游 《初夏绝句》我们在开发多Tab应用时候&#xff0c;常…

matlab数组平方的计算自定义函数_从零开始的matlab学习笔记——(38)简单数论计算函数:取整,gcd,lcm,质数,全排列...

matlab应用——求极限&#xff0c;求导&#xff0c;求积分&#xff0c;解方程&#xff0c;概率统计&#xff0c;函数绘图&#xff0c;三维图像&#xff0c;拟合函数&#xff0c;动态图&#xff0c;傅里叶变换&#xff0c;随机数&#xff0c;优化问题....更多内容尽在个人专栏&a…

bootstraptable导出excel独立使用_使用 EasyPOI 优雅导出Excel模板数据(含图片)

EasyPOI功能如同名字Easy&#xff0c;主打的功能就是容易&#xff0c;让一个没接触过POI的人员可以方便的写出Excel导出&#xff0c;Excel模板导出&#xff0c;Excel导入&#xff0c;Word模板导出。通过简单的注解和模板语言(熟悉的表达式语法)&#xff0c;完成以前复杂的写法。…

import pandas as pd什么意思_Pandas万花筒:让绘图变得更美观

全文共1803字&#xff0c;预计学习时长10分钟图源&#xff1a;tehrantimes流行 Python 数据分析库 Pandas 中的绘图功能一直是迅速绘制图表的首选之一。但是&#xff0c;其可用的可视化效果总是十分粗略&#xff0c;实用有余、美观不足。笔者常用 Pandas 的绘图功能快速地执行一…

jquery name选择器_jquery笔记

jQuery是一个封装好的特定的集合(方法和函数)。是一个库&#xff0c;封装了很多预先定义好的函数在里面。概念jQuery是一个快速&#xff0c;简洁的js库。j是js&#xff0c;query是查询&#xff0c;把js中的DOM操作作了封装&#xff0c;我们可以快速的查询使用里面的功能。jQuer…

python数据库框架_目前最受欢迎的12个Python开源框架

1 Django Django是一款用Python语言写的免费开源的 Python Web应用开发框架&#xff0c;它遵循模型 -视图-控制器(MVC)的架构模式。它是由非营利Django维护软件基金会(DSF)和3条款BSD许可下可用&#xff0c;鼓励快速发展和实用的设计。Django同时是一款在数据库功能、后台功能、…

jenkins java常用插件下载,Jenkins简单介绍以及插件入门

Jenkins是一个广泛用于持续构建的可视化web工具&#xff0c;就是各种项目的的“自动化”编译、打包、分发部署&#xff0c;将以前编译、打包、上传、部署到Tomcat中的过程交由Jenkins&#xff0c;Jenkins通过给定的代码地址&#xff0c;将代码拉取到jenkins宿主机上&#xff0c…

linux安装python3.7的步骤_Linux 安装python3.7.3

我这里使用的是Redhat6.5&#xff0c;centos系统本身默认安装有python2.x&#xff0c;版本x根据不同版本系统有所不同&#xff0c;可通过 python --V 或 python --version 查看系统自带的python版本 有一些系统命令时需要用到python2&#xff0c;不能卸载 1、安装依赖包 1&…

python画三维立体图难吗_万万没想到,Python竟能绘制出如此酷炫的三维图

作者 | Jay Alammar转载自 | 高级农民工 通常我们用 Python 绘制的都是二维平面图&#xff0c;但有时也需要绘制三维场景图&#xff0c;比如像下面这样的&#xff1a;这些图怎么做出来呢&#xff1f;今天就来分享下如何一步步绘制出三维矢量&#xff08;SVG&#xff09;图。 八…

php人物行走,非常震撼的纯CSS3人物行走动画

今天分享给大家的是一个用纯CSS3实现的人物行走动画&#xff0c;在没有使用JavaScript的情况下&#xff0c;用CSS3技术将人物行走的姿态描绘得非常逼真。其实动画实现的原理也是比较简单的&#xff0c;将人物行走时的状态分割成多张图片&#xff0c;然后利用CSS3的动画属性将这…

php jquery 弹窗提示框,jQuery实现消息弹出框效果

本文实例为大家分享了jQuery消息弹出框的具体代码&#xff0c;供大家参考&#xff0c;具体内容如下效果图实现代码.showMessage {padding: 5px 10px;border-radius: 5px;position: fixed;top: 45%;left: 45%;color: #ffffff;}.showMessageSuccess {background-color: #00B7EE;}…

python定义字符串数组_python数组声明

广告关闭 腾讯云11.11云上盛惠 &#xff0c;精选热门产品助力上云&#xff0c;云服务器首年88元起&#xff0c;买的越多返的越多&#xff0c;最高返5000元&#xff01; 如何在python? 我无法在文档中找到对数组的任何引用... 我正在制作一个小程序&#xff0c;在静态数组上保存…

python函数定义中参数列表里的参数是_python函数定义中的参数说明

原博文 2020-05-23 07:50 − > 描述函数定义时 涉及到的 位置参数&#xff0c;默认参数&#xff0c;关键字参数&#xff0c;可变参数等的概念及用法 ## 1 示例代码#! /usr/bin/env python # -*- coding: UTF-8 -*- import logging def get_default_logger(): log... 相关推荐…

我的世界手机有PHP的开服器下载,【BDS】MC基岩版官方开服器Windows版插件开发包...

您尚未登录&#xff0c;立即登录享受更好的浏览体验&#xff01;您需要 登录 才可以下载或查看&#xff0c;没有帐号&#xff1f;注册(register)xMC基岩版官方开服器Windows版插件开发教程2019年5月22日 作者&#xff1a;Player前言&#xff1a;MC基岩版官方开服器(BDS)自发布至…

c++ 协程_用yield实现协程

上一篇 理解python中的yield关键字 介绍了使用yeld实现生成器函数&#xff0c;这一篇我们来继续深入的了解一下yield&#xff0c;用yield实现协程。先来解答一下上一篇留下的问题&#xff1a;下面的代码为什么第二次调用next打印None呢&#xff1f;def 事实是这样的&#xff0c…