【Warrior刷题笔记】143.重排链表 【线性化 || 双指针+翻转链表+链表合并】详细注释
题目一 力扣143.重排链表
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/reorder-list/
1.描述
给定一个单链表L
的头节点head
,单链表 L 表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
2.示例
- 示例 1:
输入:head = [1,2,3,4]
输出:[1,4,2,3]
- 示例2
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
解法一 线性化
解题思路
题目的要求是将从尾节点开始的后半部分,重新填充到从头节点开始的前半部分,倒数第一个节点变更为正数第一个节点的后继结点,倒数第二个节点变更为正数第二个节点的尾结点,倒数第三个节点变更为正数第三个节点的尾结点。。。依此类推。单链表的缺点是无法随机访问,只能顺序访问,于是我们可以考虑将单链表变更为可随机访问的线性表,然后再对节点进行操作即可。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode *head) {
vector<ListNode*> node;//存储链表节点的线性表
ListNode* temp = head;//访问指针
while(temp){//将单链表节点存储到线性表中
node.push_back(temp);
temp = temp->next;
}
int m = node.size();//计算节点数
for(int i = 0; i < m/2; ++i){
//从i=0开始,将正数第i个节点的后继结点更新为倒数第i个节点,
//并将倒数第i+1个节点的后继节点置为空
node[m-i-2]->next=nullptr;
node[m-i-1]->next=node[i]->next;
node[i]->next=node[m-i-1];
}
}
};
复杂度分析
时间复杂度: O(m)
。m
为单链表节点数,遍历整个单链表和修改next指针指向都需要O(m)
时间。
空间复杂度: O(m)
。辅助线性表的空间消耗。
解法二 双指针+翻转链表+链表合并
解题思路
解法一的时间复杂度已为最优,但是空间复杂度仍然可以优化。如果我们使用双指针技术找到单链表后半段的头结点,然后继续使用双指针技术原地翻转单链表的后半段,最后继续使用双指针技术将链表前半段与翻转后的单链表后半段原地合并,即可将空间复杂度优化至常数级。
代码
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void reorderList(ListNode *head) {
ListNode* headRight = findRight(head);
if(!headRight) return;
headRight = reverseList(headRight);
mergeList(head,headRight);
}
ListNode* findRight(ListNode* head){//寻找链表后半段的开始节点
ListNode* verySlow = head;//用于标记前半段链表尾结点的指针
ListNode* slow = head;//慢指针,用于标记后半段链表头结点
ListNode* fast = head;//快指针
int count = 0;//计数器
while(fast){
fast = fast->next;//移动快指针
++count;//计数器加一
if(count%2==0){//每移动两次快指针就移动一次慢指针
slow =slow->next;
if(verySlow->next != slow){//除了第一次移动慢指针以外,慢指针和更慢指针都一起移动
verySlow = verySlow->next;
}
}
}
if(count<=2) return nullptr;//如果链表长度低于3,返回空指针,后续不作处理,直接结束程序
if(count%2!=0){//如果链表节点数为奇数,慢指针和更慢指针都后移一位
slow = slow->next;
verySlow = verySlow->next;
}
verySlow->next = nullptr;//将更慢指针指向节点的后继结点置为空,否则处理完毕后链表会有环
return slow;
}
ListNode* reverseList(ListNode* head){//翻转链表
ListNode* pre = nullptr;//前驱节点
ListNode* cur = head;//当前节点
while(cur){
ListNode* nextPtr = cur->next;//后继节点
cur->next = pre;//翻转
pre = cur;//更新前驱节点和当前节点
cur = nextPtr;
}
return pre;//返回翻转后的链表
}
ListNode* mergeList(ListNode* left, ListNode* right){//合并两个链表
ListNode* node = left;//用于标记前半段链表节点
while(right){
ListNode* temp = right->next;//后半段链表当前节点的后继节点
right->next = node->next;//将后半段链表当前节点置为前半段链表当前节点的后继节点
node->next = right;
node = right->next;//移动指针
right = temp;
}
return left;//返回合并后的单链表
}
};
复杂度分析
时间复杂度: O(m)
。寻找后半段节点的头结点,翻转后半段链表,合并前后段链表均为O(m)
时间。
空间复杂度: O(1)
。只需常数个额外变量。
【Warrior刷题笔记】143.重排链表 【线性化 || 双指针+翻转链表+链表合并】详细注释的更多相关文章
- 【Warrior刷题笔记】剑指offer 6 24 35. 三道题,让你学会链表递归迭代辅助栈
题目一 从尾到头打印链表 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-l ...
- 【Warrior刷题笔记】力扣169. 多数元素 【排序 || 哈希 || 随机算法 || 摩尔投票法】详细注释 不断优化 极致压榨
题目 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/majority-element/ 注意,该题在LC中被标注为easy,所以我们更多应该关 ...
- 【Warrior刷题笔记】剑指offer 32. 三道题,让你学会二叉树的深度广度优先遍历与递归迭代技术
题目一 剑指 Offer 32 - I. 从上到下打印二叉树 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-shang-dao-xi ...
- PTA刷题笔记
PTA刷题记录 仓库地址: https://github.com/Haorical/Code/tree/master/PTA/GPLT 两周之内刷完GPLT L2和L3的题,持续更新,包括AK代码,坑 ...
- 《Data Structures and Algorithm Analysis in C》学习与刷题笔记
<Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...
- Python 刷题笔记
Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...
- PAT-甲级刷题笔记和总结
本帖主要记录一些自己在刷题过程中的一些笔记,包括: 1.常用的函数 2.STL中常用方法 3.常见错误 4.其他常用方法 5.刷题过程中的常见算法:https://www.cnblogs.com/M ...
- 《剑指offer》刷题笔记
简介 此笔记为我在 leetcode 上的<剑指offer>专题刷题时的笔记整理. 在刷题时我尝试了 leetcode 上热门题解中的多种方法,这些不同方法的实现都列在了笔记中. leet ...
- LeetCode刷题笔记和想法(C++)
主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
随机推荐
- Windows 数据盘自动分区脚本
在CMD命令文本下执行,即可: diskpart //1.进入diskpart模式 list disk //2.查询磁盘 select disk 1 //3.选择磁盘 create partition ...
- 【JAVA今法修真】 第六章 天道无情,锁定乾坤
您好,我是南橘,万法仙门的掌门,刚刚从九州世界穿越到地球,因为时空乱流的影响导致我的法力全失,现在不得不通过这个平台向广大修真天才们借去力量.你们的每一个点赞,每一个关注都是让我回到九州世界的助力,兄 ...
- Windows系统安装ActiveMQ
1.下载安装包:https://activemq.apache.org/components/classic/download/ 选择自己的版本进行下载 2.安装JDK 3.把下载的ActiveMQ压 ...
- NDK编译可执行文件在Android 中运行显示error: only position independent executables (PIE) are supported.失败问题解决办法。
由于使用了NDK编译的可执行文件在应用中调用,在Android 7.0上的运行情况发现,当运行该可执行文件时,报如下错误: error: only position independent execu ...
- 【九度OJ】题目1107:搬水果 解题报告
[九度OJ]题目1107:搬水果 解题报告 标签(空格分隔): 九度OJ http://ac.jobdu.com/problem.php?pid=1107 题目描述: 在一个果园里,小明已经将所有的水 ...
- 【LeetCode】722. Remove Comments 解题报告(Python)
[LeetCode]722. Remove Comments 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/problems/remove-c ...
- [LeetCode]485. Max Consecutive Ones 找到最大的连续的1的个数
题目描述 输入只有0和1的数组(长度为正整数,且<10000),找到最大的连续1的个数 比如[1,1,0,1,1,1],输出3 思路 遍历数组,统计当前连续个数curCount和最大连续值max ...
- Docker 与 K8S学习笔记(八)—— 自定义容器网络
我们在上一篇中介绍了Docker中三种网络,none.host和bridge,除了这三种网络,Docker还允许我们创建自定义网络,当我们要创建自定义网络时,Docker提供了三种网络驱动供我们选择: ...
- TCP/IP协议竟然有这么多漏洞
网络攻击是指利用网络存在的漏洞和安全缺陷对网络系统的软硬件及其系统数据进行攻击的行为.TCP/IP协议作为网络的基础协议,从设计之初并没有考虑到网络将会面临如此多的威胁,导致出现了许多攻击方法.由于网 ...
- Linux中架构中的备份服务器搭建(rsync)
本期内容概要 Linux中的备份方式 架构中备份服务器搭建(rsync) 内容详细 1.备份方式 1. cp : 本机复制(只能作用在本机) 2. scp : 远程复制 两种模式: 推 : 本地上传到 ...