86. Partition List(分隔链表)
1. 题目描述
给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
你应当保留两个分区中每个节点的初始相对位置。
示例:
输入: head = 1->4->3->2->5->2, x = 3
输出: 1->2->2->4->3->5
2. 迭代(Iteration)
2.1 解题思路
迭代的思路非常简单:将小于x的节点串联在一个链表之中(less),把大于等于x的节点串联在另一个链表之中(greater),最后合并两个链表即可。比如题目这个例子:
head = 1->4->3->2->5->2, x = 3
less: lessHead -> 1 -> 2 -> 2;
greater: geaterHead -> 4 -> 3 -> 5
之后合并两个链表:lessHead -> 1 -> 2 -> 2 -> 4 -> 3 -> 5,这里我们也使用了假头指针的技巧,避免判断头指针的情况。只是需要注意5节点的next需指向空,否则链表可能会形成循环链表;此部分对应代码:2.2.1 不使用额外空间(推荐)
当然也可以两个queue来分别存储less和greater的节点,之后再合并链表,思路和上面是一模一样的。此部分对应代码:2.2.2 使用额外空间
2.2 实例代码
2.2.1 不使用额外空间(推荐)
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
ListNode less, greater;
ListNode* lessHead = &less, * greaterHead = &greater;
while (head) {
// 添加到before和after写法一
/*if (head->val < x) { lessHead->next = head; lessHead = lessHead->next; }
else { greaterHead->next = head; greaterHead = greaterHead->next; }*/
// 添加到before和after写法二
ListNode*& temp = head->val < x ? lessHead : greaterHead;
temp->next = head;
temp = temp->next;
head = head->next;
}
lessHead->next = greater.next; // 合并两个链表
greaterHead->next = nullptr;
return less.next;
}
};
2.2.2 使用额外空间
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
queue<ListNode*> less;
queue<ListNode*> greater;
while (head) {
if (head->val < x) less.push(head);
else greater.push(head);
head = head->next;
}
// less和greater进行合并
while (greater.size()) { less.push(greater.front()); greater.pop(); }
// 生成分隔后的链表
if (less.size()) { head = less.front(); less.pop(); }
ListNode* cur = head;
while (less.size()) { cur->next = less.front(); less.pop(); cur = cur->next; }
if (cur) cur->next = nullptr; // corner case: [], 0
return head;
}
};
3. 递归(Recursion)
3.1 解题思路
递归的方法稍微要难一点,不如迭代那么清晰。递归的关键是从后往前找到:head->val > head->next->val && head->next->val < x,这里表示head是大于等于x的,而head->next是小于x的,比如:5 -> 2, x = 3。所以存在这样一个节点,我们需要向后检查,把所有的小于x的值移动到前面,大于等于x的值移动到后面。递归过程如下图所示:
3.2 实例代码
class Solution {
void dfs(ListNode* head, int x) {
if (!head || !head->next) return;
dfs(head->next, x); // 找到最后一个节点
if (head->val >= x) {
// 将小于x的值向前移动,大于等于x的值向后移动
while (head->next) {
if (head->val > head->next->val && head->next->val < x) {
int temp = head->val; head->val = head->next->val; head->next->val = temp; // 交换两个节点的值
head = head->next;
}
else break;
}
}
}
public:
ListNode* partition(ListNode* head, int x) {
dfs(head, x);
return head;
}
};