文章目录
- 24. 两两交换链表中的节点
- 题目
- 算法原理
- 代码实现
- 143. 重排链表
- 题目
- 算法原理
- 代码实现
题目链接: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. 重排链表
给定一个单链表 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
链表的题目一般就是模拟或者递归,此题我们模拟。
这里重排可以看作找到链表的中间节点,前面部分正常排列,后面部分逆序一下,然后将两个部分一个接一个插入新链表
这样就分三步:
这题的知识点很综合!!!一题抵三题
/**
* 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;
}
};
运行结果: