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.
For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.
思路:
1. 用两个指针,一个指针放在连续小于x的最右边界,一个遍历去发现后面位置小于x的节点,然后把这个节点插入到前面位置,并删除。
2. 头节点可能改变,所以用dummy node或pointer to pointer两个方法。
3. 上面思路,太繁复了,最终也没调试出来。仔细思考,这道题涉及两件事:一是链表;一是数据分组。两件事放一块,怎么利用两件事的特点?
4. 先看看如果是vector,如何对数据分组?如果允许分配新的空间,可以分配两个空的vector,遍历一遍,把小于x的数push进一个vector,而大于x的push进另一个vector,最后把这一个vector插入到另一个的后面即可;如果需要in place,这从左往右遍历,每次遇到小于x的数都不断和左侧数交换位置,直到左侧数也小于x,这样做的复杂度就是o(n^2).
5. 链表的特点就是节点可以任意移动,只需要改变节点的指针即可,省空间。所以,用上文vector的方法1可以不用新建两个list,而只需要建立两个头节点,然后分别用指针指向头节点,然后遍历链表:遇到小于x的节点则直接把这个节点放在新建的头节点后面,头节点指针往后移动;遇到大于x的节点则放在另一个头节点后面。等放完后,原来的链表就分别放到两个链表里了。这是只需要把两个链表链接起来即可!
调试
- 需要强调的是,对运算中涉及的指针,要有意识去检查运算完成或循环最后一次的状态,比如:这道题,就可能没有检查指针的值,而导致cycle出现。
//方法2:链表操作新的思路!
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//
ListNode s(0),l(0);//s:small,l:large
ListNode*ps=&s,*pl=&l;
while(head){
if(head->val<x){
ps->next=head;
ps=ps->next;
}else{
pl->next=head;
pl=pl->next;
}
head=head->next;
}
//if(ps->next)
ps->next=l.next;//善始善终,考虑了ps->next的去处,还要考虑pl的去处
pl->next=NULL;//这句代码表示上面把一个链表拆成两个链表还不完全,
//在上面while最后一次循环,两个链表仍藕断丝连,
//需要在返回前把两个disconnect,否则有cycle存在!!!
return s.next;
}
};
//方法1:被抛弃的方法
class Solution {
public:
ListNode* partition(ListNode* head, int x) {
//
ListNode**p=&head,*pnow=head;
while((*p)->val<x){
*p=(*p)->next;
}
pnow=*p;
while(pnow){
while(pnow->next&pnow->next->val>=x)
pnow=pnow->next;
if(pnow->next){
ListNode*tmp=*p;
*p=pnow->next;
pnow->next=pnow->next->next;
(*p)->next=tmp;
p=&((*p)->next);
}
}
return head;
}
};