Leetcode 86. Partition List

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的节点则放在另一个头节点后面。等放完后,原来的链表就分别放到两个链表里了。这是只需要把两个链表链接起来即可!

调试
  1. 需要强调的是,对运算中涉及的指针,要有意识去检查运算完成或循环最后一次的状态,比如:这道题,就可能没有检查指针的值,而导致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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值