文章目录
- 🥝24. 两两交换链表中的节点
- 🥑题目
- 🌽算法原理
- 🥬代码实现
- 🍎143. 重排链表
- 🍒题目
- 🍅算法原理
- 🍓代码实现
🥝24. 两两交换链表中的节点
🥑题目
题目链接:24. 两两交换链表中的节点
给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)。
示例 1:
输入:head = [1,2,3,4]
输出:[2,1,4,3]
示例 2:
输入:head = []
输出:[]
示例 3:
输入:head = [1]
输出:[1]
提示:
- 链表中节点的数目在范围
[0, 100]
内 0 <= Node.val <= 100
🌽算法原理
解法一:迭代(模拟)
做链表相关的题目,不要**吝啬空间!!!**这里我们先建立一个虚拟头节点,这样可以一视同仁第一个交换的和后面交换的。
每次交换会涉及到四个节点的修改,即要交换的2个节点和它们前后的两个节点,这里也不吝啬空间,这就创建4个临时变量。
何时终止交换:
- 当链表节点个数为偶数的时候,
cur
为空的时候停止交换- 当链表节点个数为奇数的时候,
next
为空的时候,停止交换
解法二:递归
从宏观的角度,将递归看作一个黑盒,相信它一定能完成任务,我们的任务就是让它帮我们完成节点的两两交换
先交换后面的节点,然后把前面的节点连接起来即可。
🥬代码实现
迭代:
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head){if(head == nullptr || head->next == nullptr) return head;ListNode* newHead = new ListNode(0);newHead->next = head;ListNode* prev = newHead;ListNode* cur = prev->next;ListNode* next = cur->next;ListNode* nnext = next->next;while(cur && next){//交换prev->next = next;next->next = cur;cur->next = nnext;//修改指针prev = cur;cur = nnext;if(cur) next = cur->next;if(next) nnext = next->next; }prev = newHead->next;delete newHead;return prev;}
};
运行结果:
递归:
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:ListNode* swapPairs(ListNode* head){if(head == nullptr || head->next == nullptr) return head;auto tmp = swapPairs(head->next->next);auto ret = head->next;head->next->next = head;head->next = tmp;return ret;}
};
🍎143. 重排链表
🍒题目
题目链接:143. 重排链表
给定一个单链表 L
的头节点 head
,单链表 L
表示为:
L0 → L1 → … → Ln - 1 → Ln
请将其重新排列后变为:
L0 → Ln → L1 → Ln - 1 → L2 → Ln - 2 → …
不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。
示例 1:
输入:head = [1,2,3,4]
输出:[1,4,2,3]
示例 2:
输入:head = [1,2,3,4,5]
输出:[1,5,2,4,3]
提示:
- 链表的长度范围为
[1, 5 * 104]
1 <= node.val <= 1000
🍅算法原理
链表的题目一般就是模拟或者递归,此题我们模拟。
这里重排可以看作找到链表的中间节点,前面部分正常排列,后面部分逆序一下,然后将两个部分一个接一个插入新链表
这样就分三步:
- 找到链表的中间节点(快慢指针)
leetcode – 876.链表的中间节点 - 后面部分逆序
- 合并链表
这题的知识点很综合!!!一题抵三题
🍓代码实现
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
class Solution {
public:void reorderList(ListNode* head){//找中间节点ListNode* slow = head, *fast = head;while(fast && fast->next){slow = slow->next;fast = fast->next->next;}//从slow->next开始逆序ListNode* headMid = new ListNode(0);ListNode* cur = slow->next;slow->next = nullptr;while(cur){ListNode* next = cur->next;cur->next = headMid->next;headMid->next = cur;cur = next;}//合并链表ListNode* ret = new ListNode(0);ListNode* prev = ret;ListNode*cur1 = head, *cur2 = headMid->next;while(cur1) //cur1的长度>=cur2的长度{prev->next = cur1;cur1 = cur1->next;prev = prev->next;if(cur2){prev->next = cur2;cur2 = cur2->next;prev = prev->next;}}delete ret;delete headMid;}
};
运行结果: