【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刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
随机推荐
- [BUUCTF]REVERSE——[ACTF新生赛2020]easyre
[ACTF新生赛2020]easyre 附件 步骤 查壳,32位程序,upx壳儿 脱完壳儿,扔进ida 分析 一开始给我们定义了一个数组, v4=[42,70,39,34,78,44,34,40,73 ...
- [BUUCTF]PWN——[Black Watch 入群题]PWN
[Black Watch 入群题]PWN--栈劫持 入群题密码在 /password.txt Ubuntu 16 2020年02月27日:此入群题已作废,请看新版入群题. 附件 解题步骤: 例行检查, ...
- [BUUCTF]PWN14——not_the_same_3dsctf_2016
[BUUCTF]PWN14--not_the_same_3dsctf_2016 题目网址:https://buuoj.cn/challenges#not_the_same_3dsctf_2016 步骤 ...
- idea删除同一个模块后新建模块显示被占用
当我们某个模块因为什么原因需要删除重建的时候 ,输入完模块名称并不能创建出来,这是因为模块已经被注册 解决办法: 1.右键点击项目名称---选择Load/Unload Modules 2.将已经删除的 ...
- Oracle不等于符号过滤null情况
在Oracle查询过程中,条件查询时,用"<>"操作符进行查询会过滤掉字段为null的记录. 一.不使用"<>"操作符查询:select ...
- 网络编程之UDP(2)linux查看socket默认缓冲区大小和最大值
默认值 命令: cat /proc/sys/net/core/rmem_default 结果: 最大值 命令: cat /proc/sys/net/core/rmem_max 结果:
- 【LeetCode】954. Array of Doubled Pairs 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 「HAOI2016」找相同字符
知识点: SA,线段树,广义 SAM 原题面 Loj Luogu 给定两字符串 \(S_1, S_2\),求出在两字符串中各取一个子串,使得这两个子串相同的方案数. 两方案不同当且仅当这两个子串中有一 ...
- Normalization Methods
目录 概 主要内容 Batch Normalization Layer Normalization Instance Normalization Group Normalization Ioffe S ...
- On the Optimization of Deep Networks: Implicit Acceleration by Overparameterization
目录 引 主要内容 定理1 Claim 1 Claim 2 定理2 证明 定理1的证明 Claim 1 的证明 Kronecker product (克罗内克积) Theorem 2 的证明 代码 A ...