【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刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...
随机推荐
- pycharm的破解和基本使用
pycharm的破解 pycharm的账号注册 在完成安装后打开pycharm软件,需要选择购买或是使用.点击试用,选择进入官网注册账号. 进入官网后选择邮箱登录,输入自己的邮箱,点击sign up ...
- Kerberos认证
http://www.cnblogs.com/artech/archive/2011/01/24/kerberos.html 最近一段时间都在折腾安全(Security)方面的东西,比如Windows ...
- 自定义函数(Power Query 之 M 语言)
数据源: 任意工作簿 目标: 使用自定义函数实现将数据源导入Power Query编辑器 操作过程: PowerQuery编辑器>主页>新建源>其他源>空查询 编辑栏内写入公式 ...
- OpenWrt之DNS设置
目录 OpenWrt之DNS设置 0.前言 1.WAN口 2.Lan口 3.LAN口DHCP选项 4.DHCP/DNS 5.总结 参考(Thanks) 附录.DHCP OPTION OpenWrt之D ...
- sqlalchemy-orm学生签到 成绩记录查询系统
#!/usr/bin/env python # Author:zhangmingda '''''' from sqlalchemy import create_engine,ForeignKey,DA ...
- PDF 补丁丁开放源代码
PDF补丁丁是一个多功能的 PDF 文档工具箱,在 2009 年开始,我开始了该程序的开发,到现在也已经有十二年了.它致力于解除 PDF 文档的烦恼,带有一个强大的 PDF 书签编辑器(可自动生成书签 ...
- 【剑指Offer】扑克牌顺子 解题报告(Python)
[剑指Offer]扑克牌顺子 解题报告(Python) 标签(空格分隔): 剑指Offer 题目地址:https://www.nowcoder.com/ta/coding-interviews 题目描 ...
- 1188 最大公约数之和 V2
1188 最大公约数之和 V2 题目来源: UVA 基准时间限制:2 秒 空间限制:262144 KB 给出一个数N,输出小于等于N的所有数,两两之间的最大公约数之和. 相当于计算这段程 ...
- ZOJ 3870:Team Formation(位运算&思维)
Team Formation Time Limit: 2 Seconds Memory Limit: 131072 KB For an upcoming programming contest, Ed ...
- Laravel 使用 maatwebsite/excel 时长数字出现科学计数法的解决办法
在使用 maatwebsite/excel 包导出Excel的时候,有的单元格里会存放手机号等一大串的数字,这一串数字会被Excel软件处理为科学计数法,在后续处理数据的时候会产生不小的麻烦,一个个去 ...