Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.
You should preserve the original relative order of the nodes in each of the two partitions.
Example:
Input: head = 1->4->3->2->5->2, x = 3 Output: 1->2->2->4->3->5
方法一
双指针的思路,p->next指向小于x的节点要插入的位置,q向后遍历找到小于x的节点并把它赋给p->next。一开始,p先从左到右找到第一个大于等于x的节点,例如上面的例子里,p指向1,p->next指向4;q继续向后走,走到q->next等于2的时候停下,q指向3。将q->next(3)的节点转移到p->next上去,链表变为
1->2->4->3->5->2
之后更新p和q,p指向2, p->next指向4,q指向3。
还有一个问题需要解决,那就是插入到链表头部的情况。可以在函数一开始就引入一个节点node,node->next = head然后在node上操作,返回的时候返回node->next,这样就不用处理这个特殊情况了。我代码中的方法更复杂,没有引入这个node而是手动判断插到头部的情况并更新head。
ListNode* partition(ListNode* head, int x) {
if (!head) {
return head;
}
ListNode *p, *q, *newHead;
p = q = newHead = head;
if (p->val < x) {
while (p->next && p->next->val < x) {
p = p->next;
}
}
q = p;
while (q->next) {
while (q->next && q->next->val >= x) {
q = q->next;
}
if (q->next) {
ListNode *small = q->next;
// small -> node whose value is less than x, it will be moved to the front of list
if (p == newHead && p->val >= x) {
q->next = q->next->next;
small->next = p;
newHead = small;
p = newHead;
}
else {
ListNode *tmp; // tmp -> the node rightside of where the small node will insert
tmp = p->next;
q->next = q->next->next;
p->next = small;
small->next = tmp;
p = p->next;
}
}
else
break;
}
return newHead;
}
方法二
看了LC Discuss里面别人的方法,很受启发。更简单的方法是维护两个子链表,一个全部小于x,一个大于等于x,最后将后面的链表接在前面的链表的尾部。例如上面的例子中,p1: 1->2->2,p2:4->3->5。最后把p2接在p1后面就行了。这个方法比我上面的方法简单多了,自然代码里行数就少了很多。
ListNode *partition(ListNode *head, int x) {
ListNode node1(0), node2(0);
ListNode *p1 = &node1, *p2 = &node2;
while (head) {
if (head->val < x)
p1 = p1->next = head;
else
p2 = p2->next = head;
head = head->next;
}
p2->next = NULL;
p1->next = node2.next;
return node1.next;
}
总结:链表的问题要用链表的思路考虑,我的方法一在很大程度上还是受到解决数组问题的思路的影响,双指针的影子非常强。Remove Duplicates in Sorted List 里面我也是一开始拿处理数组的方式来处理链表,用双指针把没有duplicate的节点全部移到左边,导致代码写起来比较复杂、容易出错,看了别人的方法后才有了一种豁然开朗的感觉,原来可以直接跳过中间那些节点。这两道问题的链表和数组版本很锻炼两种思考方式,感觉还是很需要经常回顾来慢慢培养解题思路的。