题目一 力扣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.重排链表 【线性化 || 双指针+翻转链表+链表合并】详细注释的更多相关文章

  1. 【Warrior刷题笔记】剑指offer 6 24 35. 三道题,让你学会链表递归迭代辅助栈

    题目一 从尾到头打印链表 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-l ...

  2. 【Warrior刷题笔记】力扣169. 多数元素 【排序 || 哈希 || 随机算法 || 摩尔投票法】详细注释 不断优化 极致压榨

    题目 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/majority-element/ 注意,该题在LC中被标注为easy,所以我们更多应该关 ...

  3. 【Warrior刷题笔记】剑指offer 32. 三道题,让你学会二叉树的深度广度优先遍历与递归迭代技术

    题目一 剑指 Offer 32 - I. 从上到下打印二叉树 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/cong-shang-dao-xi ...

  4. PTA刷题笔记

    PTA刷题记录 仓库地址: https://github.com/Haorical/Code/tree/master/PTA/GPLT 两周之内刷完GPLT L2和L3的题,持续更新,包括AK代码,坑 ...

  5. 《Data Structures and Algorithm Analysis in C》学习与刷题笔记

    <Data Structures and Algorithm Analysis in C>学习与刷题笔记 为什么要学习DSAAC? 某个月黑风高的夜晚,下班的我走在黯淡无光.冷清无人的冲之 ...

  6. Python 刷题笔记

    Python 刷题笔记 本文记录了我在使用python刷题的时候遇到的知识点. 目录 Python 刷题笔记 选择.填空题 基本输入输出 sys.stdin 与input 运行脚本时传入参数 Pyth ...

  7. PAT-甲级刷题笔记和总结

     本帖主要记录一些自己在刷题过程中的一些笔记,包括: 1.常用的函数 2.STL中常用方法 3.常见错误 4.其他常用方法 5.刷题过程中的常见算法:https://www.cnblogs.com/M ...

  8. 《剑指offer》刷题笔记

    简介 此笔记为我在 leetcode 上的<剑指offer>专题刷题时的笔记整理. 在刷题时我尝试了 leetcode 上热门题解中的多种方法,这些不同方法的实现都列在了笔记中. leet ...

  9. LeetCode刷题笔记和想法(C++)

    主要用于记录在LeetCode刷题的过程中学习到的一些思想和自己的想法,希望通过leetcode提升自己的编程素养 :p 高效leetcode刷题小诀窍(这只是目前对我自己而言的小方法,之后会根据自己 ...

随机推荐

  1. [WPF] 用 OpacityMask 模仿 UWP 的 Text Shimmer 动画

    1. UWP 的 Text Shimmer 动画 在 UWP 的 Windows Composition Samples 中有一个 Text Shimmer 动画,它用于展示如何使用 Composit ...

  2. inndy_rop

    又学习到了一个新知识 拿到题目例行检查,发现是32位的程序,放入ida中 进入main看到了一个overflow函数进入查看 存在明显的栈溢出,看到题目知道要用rop来做,但是完全没有思路, 后来发现 ...

  3. int i=i++;和i=++i;和i++

    1.int i=i++; 2.i=++i; 3.i++

  4. CF740B Alyona and flowers 题解

    Content 有 \(n\) 个数 \(a_1,a_2,a_3,...,a_n\),给定 \(m\) 个区间,你可以选择一些区间使得它们的总和最大(也可以不选),求这个最大的总和. 数据范围:\(1 ...

  5. AT5341 [ABC156D] Bouquet 题解

    Content 有一个人有 \(n\) 种不同的话可供选择,TA 可以选择至少一种花做花束,但是 TA 不喜欢花的种数为 \(a\) 或者 \(b\) 的花束.求选花的方案数对 \(10^9+7\) ...

  6. java 图形化小工具Abstract Window Toolit 常用组件:对话框Dialog FileDialog

    对话框 Dialog是Window类的子类,是1个容器类,属于特殊组件,对话框是可以独立存在的顶级窗口,因此用法与普通窗口的用法几乎完全一样.但对话框有如下两点需要注意. (1),对话框通常依赖于其他 ...

  7. JAVA整合kaptcha生成验证码 (字母验证码和算术验证码)

    引入maven <!--图片验证码--> <dependency> <groupId>com.github.penggle</groupId> < ...

  8. 【LeetCode】986. Interval List Intersections 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双指针 日期 题目地址:https://leetco ...

  9. 【LeetCode】337. House Robber III 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  10. 【jvm】08-垃圾回收器那么多傻傻分不清?

    [jvm]08-垃圾回收器那么多傻傻分不清? 欢迎关注b站账号/公众号[六边形战士夏宁],一个要把各项指标拉满的男人.该文章已在github目录收录. 屏幕前的大帅比和大漂亮如果有帮助到你的话请顺手点 ...