链表反转问题
对于链表问题的求解,大体做法是画出图一步一步分析。一般都可以进行原地操作(即额外空间复杂度为O(1))。
问题一:反转链表
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
迭代求解
定义三个指针,记做pre,cur,next。其初值为
pre = head
pre.next = null
cur = head.next
next = null
迭代过程中先使用next存储当前位置的下一个结点,再让当前位置指向其前一个节点,然后更新前一个节点跟新当前结点。
图解如下:
代码如下:
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode pre = head;
ListNode cur = head.next;
pre.next = null;
ListNode next = null;
while(cur != null){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
return pre;
}
}
时间复杂度O(N),额外空间复杂度O(1)
递归求解
对于一个节点,首先将其后续结点完成反转,再将其连到反转后的后续结点之后。
递归结束条件:当前结点不存在后续结点,直接返回其本身即可。
图解如下:
上述图的当前结点为首结点的情况。
代码实现中对于后续结点我们既想知道其反转后的头结点又想知道其反转后的尾结点,因此使用一大小为2的一维数组作为递归的返回值,其中第一个元素为后溪结点反转后的头结点,第二个元素为其尾节点。
代码如下:
class Solution {
public ListNode reverseList(ListNode head) {
if(head == null){
return null;
}
ListNode[] info = reverse(head);
return info[0];
}
// info[0] 为反转后的头结点, info[1] 为反转后的尾结点
public ListNode[] reverse(ListNode head){
if(head.next == null){
return new ListNode[]{head, head};
}
ListNode[] info = reverse(head.next);
head.next = null;
info[1].next = head;
return new ListNode[]{info[0], head};
}
}
时间复杂度O(N),额外空间复杂度O(1)
问题二:两两交换链表结点
给定一个链表,两两交换其中相邻的节点,并返回交换后的链表。
示例:
给定 1->2->3->4, 你应该返回 2->1->4->3.
其中该问题就是问题一的升级版,只不过时两个两个反转,因此每次两个两个往前走。
图解如下:
为了清楚期间上述图解并未考虑不链表长度为奇数的情况,对于该情况的最后一个结点将其接到之前反转后的链表的后面即可。
代码如下:
class Solution {
public ListNode swapPairs(ListNode head) {
if(head == null || head.next == null){
return head;
}
ListNode newHead = head.next;
ListNode pre = head;
ListNode cur = head.next;
head.next = null;
ListNode next = null;
while(cur != null){
next = cur.next;
cur.next = pre;
if(next == null || next.next == null){
pre.next = next;
break;
}
pre.next = next.next;
pre = next;
cur = pre.next;
pre.next = null;
}
return newHead;
}
}
时间复杂度O(N),额外空间复杂度O(1)
问题三:K个一组反转链表
给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
说明:
你的算法只能使用常数的额外空间。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
该问题是问题一,问题二的一般化。
使用递归求解 + 迭代求解。整体上进行递归,而递归内部反转K个结点使用迭代。
对于当前头结点,首先判断该链表长度是否不小于K,若小于k直接返回即可,对于不小于k的情况,先对该链表的k个结点进行反转,然后对K+1个结点进行上述操作。
class Solution {
public ListNode reverseKGroup(ListNode head, int k) {
ListNode temp = head;
for(int i = 0; i < k; i++){
if(temp == null){
return head;
}
temp = temp.next;
}
ListNode cur = head.next;
ListNode pre = head;
pre.next = null;
ListNode next = null;
// 对k个结点反转,k - 1次即可
for(int i = 0; i < k - 1; i++){
next = cur.next;
cur.next = pre;
pre = cur;
cur = next;
}
head.next = reverseKGroup(cur, k);
return pre;
}
}
时间复杂度O(N),额外空间复杂度O(1)
- Enterprise Library深入解析与灵活应用(8):WCF与Exception Handling AppBlock集成[上]
- 苹果就“电池门”公开致歉;微信下拉任务栏新增小游戏;美团打车进入北京
- 新华三《中国城市数字经济指数白皮书》:深圳数字经济发展水平国内居首
- NodeMCU模块写入MicroPython固件
- 如何证明Application Domain的隔离性
- Enterprise Library深入解析与灵活应用(8):WCF与Exception Handling AppBlock集成[下]
- 我所理解的Remoting(1):Marshaling & Activation[上篇]
- oracle 12c 常见报告获取-AWR
- 人人公司收购美国卡车社区 Trucker Path,未来或探索无人驾驶
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[下篇]
- 《WCF的绑定模型》博文系列汇总[共6篇]
- 快来看看难民营里的高科技超市
- WCF技术剖析之二十三:服务实例(Service Instance)生命周期如何控制[中篇]
- 如何通过自定义MessageFilter的方式利用按键方式操作控件滚动条[附源代码]
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Java正则表达式匹配日期及基本使用
- VM虚拟机中linux centOS 联网单网卡配置教程
- Python操作redis数据库
- pytest 测试框架学习(1):初识
- 爬虫工程师也应该会的 NodeJS 知识(三)- 快速抛弃 execjs
- 八皇后问题Python实现
- 进击吧!Pythonista(6/100)
- 进击吧!Pythonista(9/100)
- 数据结构基础(一)数组,矩阵
- pytest 测试框架学习(3):pytest.approx
- pytest 测试框架学习(4):pytest.fail
- SpringBoot 开发秘籍 - 启动时配置校验
- pytest 测试框架学习(5):pytest.skip
- pytest 测试框架学习(6):pytest.importorskip
- Java 自定义注解及使用场景