LeetCode 92 | 大公司常考的面试题,翻转链表当中指定部分
今天是LeetCode专题的第58篇文章,我们一起来看看LeetCode 92题,翻转链表II(Reverse LInked List II)。
这题的官方难度是Medium,2451个赞同,145个反对,通过率38.6%。从这份数据上我们也看得出来,这题的质量很高,广受好评。也的确如此,这是一道非常经典的链表问题,不仅考验我们对于链表的理解和掌握,而且对基本功的要求也很高。
题意
给定一个链表和两个整数m和n,m和n分别代表链表当中的第m和第n个元素,其中m <= n。要求我们通过一次遍历将链表当中m到n这一段元素进行翻转。
样例
Input: 1->2->3->4->5->NULL, m = 2, n = 4
Output: 1->4->3->2->5->NULL
题解
这题的题意很直接,就是让我们翻转链表当中指定的部分,并且只能通过一次遍历完成。
我们很容易想明白,通过m和n我们可以将链表分成三个部分:

分别是m左侧的,m到n之间的也就是我们需要翻转的部分,以及n右侧的部分。当然这里可能存在一个特殊情况,m左侧和n的右侧都有可能没有元素,我们可以先忽略,先考虑最一般的情况。
翻转链表我们最常用的方法就是先把[m, n]区间里的元素先存储起来,人工翻转了之后,再重新构建成一段链表,替换原链表对应的部分。但是很明显也可以发现,这样做是不符合题目要求的。因为我们存储元素遍历了链表一次,我们在构建链表的时候又遍历了一次,至少需要两次遍历才可以完成。
那怎么样才能一次遍历完成链表的翻转呢?其实也很简单,我们只需要倒叙插入就好了。
比如我们有这样一段链表,我们想要翻转其中2、3、4这三个节点:

首先,我们从1开始,1是翻转之后的起始部分。我们先记录下1的位置,这里1指向2保持不变。对于2号节点我们需要记录下它的后继,这里我们用tmp记录2号节点的后继,也就是3号节点。之后我们将2号节点的后继置为None。

再下一步,我们用tmp记录3号节点的后继,将3号节点的后继指向2号节点。

最后,我们如法炮制,将4号节点的后继指向3号节点,将1号节点的后继指向4号节点,并且将2号节点的后继指向4号节点的原后继,也就是None。这样我们就完成了链表部分的翻转,其中的原理很简单,就是利用了链表遍历和插入时候的性质,每次将需要翻转部分元素的后继指向它们原本的前驱。这句话有些拗口,但是多读几遍也就理解了。

这个思路非常简单,但是用代码实现却不容易,很容易写错。尤其是在赋值的时候,很容易搞错指针到底应该指向哪里,到底需要哪些临时变量。关于这些内容没有太好的办法,只能加强训练,提升自己的基本功。
最后, 我们考虑一下特殊情况。题目当中的特殊情况有两种, 第一种是m=1,第二种是n=链表末尾。其中第二种不算是特殊情况,因为在链表当中末尾的元素也有后继,就是None。但是m=1的情况需要小心,因为m=1的时候,翻转部分是没有前驱的,稍稍有些不同。解决也很简单,我们单独特判一下这种情况,人为创建一个前驱节点即可。
贴上代码:
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def reverseBetween(self, head: ListNode, m: int, n: int) -> ListNode:
if m == n:
return head
pnt = head
# 移动m-2格,到达翻转部分的前驱节点
for i in range(m-2):
pnt = pnt.next
flag = False
# 特判m=1的情况,如果m=1那么人为制造一个节点作为前驱
if m == 1:
flag = True
pnt = ListNode(0)
pnt.next = head
head = pnt
# cur即当前待翻转的节点
cur = pnt.next
# pre表示cur的前驱
pre = pnt
# last表示最后一个翻转的元素
last = pnt.next
for i in range(m, n+1):
# 先记录下当前节点的后继
nxt = cur.next
# 将当前节点的后继指向前驱
cur.next = pre
pnt.next = cur
pre = cur
cur = nxt
# 将last指向翻转之后的元素,将链表串起来
last.next = cur
return head.next if flag else head
总结
链表的相关操作非常考验基本功,虽然算法简单,但是对链表不熟悉,逻辑思考能力稍稍弱一些的同学想要做出这道题还是比较困难的。也因此,很多公司在面试的时候喜欢询问链表相关的操作和算法,以此考察候选人的基本功。如果想要进入大公司的,建议好好练习一下相关的问题,一定会有帮助的。
今天的文章到这里就结束了,如果喜欢本文的话,请来一波素质三连,给我一点支持吧(关注、转发、点赞)。
- END -
LeetCode 92 | 大公司常考的面试题,翻转链表当中指定部分的更多相关文章
- 近5年常考Java面试题及答案整理(三)
上一篇:近5年常考Java面试题及答案整理(二) 68.Java中如何实现序列化,有什么意义? 答:序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化.可以对流化后的对象进行读写 ...
- 近5年常考Java面试题及答案整理(二)
上一篇:近5年常考Java面试题及答案整理(一) 31.String s = new String("xyz");创建了几个字符串对象? 答:两个对象,一个是静态区的"x ...
- 各大公司java后端开发面试题
各大公司Java后端开发面试题总结 ThreadLocal(线程变量副本)Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量.采用空间换时间,它用于线程间的数据隔离 ...
- [LeetCode] Reverse Nodes in k-Group 每k个一组翻转链表
Given a linked list, reverse the nodes of a linked list k at a time and return its modified list. If ...
- 各大公司Java后端开发面试题总结
ThreadLocal(线程变量副本)Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量.采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一个副 ...
- 近5年常考Java面试题及答案整理(一)
下列面试题都是在网上收集的,本人抱着学习的态度找了下参考答案,有不足的地方还请指正. 1.面向对象的特征有哪些方面? 抽象:将同类对象的共同特征提取出来构造类. 继承:基于基类创建新类. 封装:将数据 ...
- 面试题:各大公司Java后端开发面试题总结 已看1 背1 有用 链接有必要看看
ThreadLocal(线程变量副本) --整理 Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量. 采用空间换时间,它用于线程间的数据隔离,为每一个 ...
- (最新)各大公司Java后端开发面试题总结
ThreadLocal(线程变量副本) Synchronized实现内存共享,ThreadLocal为每个线程维护一个本地变量. 采用空间换时间,它用于线程间的数据隔离,为每一个使用该变量的线程提供一 ...
- C/C++常考基础面试题(更新)
题目来自牛客网 解析部分来自牛客网 https://www.nowcoder.com/4685265 一 分析下面代码有什么问题? void test1() { char string[10]; ch ...
随机推荐
- Spring Security 实战干货:图解用户是如何登录的
1. 前言 欢迎阅读Spring Security 实战干货系列文章,在集成Spring Security安全框架的时候我们最先处理的可能就是根据我们项目的实际需要来定制注册登录了,尤其是Http登录 ...
- CentOS7.3 ffmpeg安装
ffmpeg安装笔记 ======================== 一.安装依赖 yum -y install yum-utils yum-config-manager --add-repo ht ...
- Qt高级编程 高清PDF+源|网盘下载地址附提取码|
书籍作者:Mark Summerfield(马克 . 萨默菲尔德)(英) 书籍译者:闫锋欣内容简介:本书是一本阐述Qt高级编程技术的书籍.本书以工程实践为主旨,是对Qt现有的700多个类和上百万字 ...
- yield 复习
1.协程,微型进程: yield 生成器 yield 会保存声明的变量,可以进行迭代 使用 接收函数返回的对象.__next__() next(接收函数返回的对象) .send() 方法 传递给函数中 ...
- 5分钟白嫖我常用的免费效率软件/工具!效率300% up!
Mac 免费效率软件/工具推荐 1. uTools(Windows/Mac) 还在为了翻译 English 而专门下载一个翻译软件吗? 还在为了格式某个 json 文本.时间戳转换而打开网址百度地址吗 ...
- odoo自定义模块项目结构,odoo自定义模块点安装不成功解决办法
如图所示:在odoo源码的根目录中创建自己的项目文件(project) 在odoo.conf配置文件中的addons_path路径中加入自己项目的文件夹路径,推荐使用绝对路径 addons_path ...
- windows:shellcode 远程线程hook/注入(一)
https://www.cnblogs.com/theseventhson/p/13199381.html 上次分享了通过APC注入方式,让目标线程运行shellcode.这么做有个前提条件:目标线程 ...
- [转]Post和Get的区别
作者:zhanglinblog 来源:https://urlify.cn/FnYBbu 这个问题几乎面试的时候都会问到,是一个老生常谈的话题,然而随着不断的学习,对于以前的认识有很多误区,所以 ...
- 利用Data Vault对数据仓库进行建模(二)
写在前面 本篇先不讨论Data Vault其本身,因为不见得所有人都接受这个.但是里边有一些很不错的东西跟主流的数据仓库方法是有共同点的,所以这里主要讨论这些共同的方法,在笔者看来,无论是Kimbal ...
- 使用Flask开发简单接口(5)--数据加密处理
前言 在之前开发的接口中,我们设计把用户信息存储到数据库时,没有对数据进行加密处理,为了提高下安全性,我们今天就学习下,如何对用户数据进行加密加盐处理. MD5加密加盐 MD5加密 MD5是常用的一种 ...