LC 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.

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的节点全部移到左边,导致代码写起来比较复杂、容易出错,看了别人的方法后才有了一种豁然开朗的感觉,原来可以直接跳过中间那些节点。这两道问题的链表和数组版本很锻炼两种思考方式,感觉还是很需要经常回顾来慢慢培养解题思路的。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值