LeetCode面试题02.04分割链表和86分隔链表题解总结

面试题02.04、分割链表

在这里插入图片描述
其实我自己一开始看到这个题目的时候,是一脸懵* 的,后来结合着英文版的题目,才把题目意思给搞懂。个人觉得,主要是这个示例整的,让人有点迷。我觉得应该加上一句:答案不唯一或者左右部分内部节点无顺序要求。(即不必考虑元素的相对位置)

题目的意思就是:把小于x的节点放在大于或等于x对的节点的前面。
例如: [1,4,3,2,5,2] 3 -> [1, 2, 2, 3, 4, 5]
[3, 5, 8, 5, 10, 2, 1] 5 -> [1, 2, 3, 5, 5, 8, 10]

方法:双指针
cur是遍历的当前节点,pre为遍历中第一个未交换的节点。
cur向后遍历过程中,若遇到小于x的元素,就将cur的val与pre的val进行交换;否则,就一直往下遍历,直到链表尾。
例如: [3, 5, 8, 5, 10, 2, 1] 5 -> [3, 2, 1, 5, 10, 5, 8],个人的思路笔记如下:
在这里插入图片描述

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
 class Solution{
public:
    void swap(ListNode* pre, ListNode* cur){
        if(pre == NULL || cur == NULL)   return;
        int tmp = pre->val;
        pre->val = cur->val;
        cur->val = tmp;
    }

    ListNode* partition(ListNode* head, int x){
        if(head == NULL)  return NULL;   
        ListNode* cur = head;
        ListNode* pre = head;
        while(cur){
            if(cur->val < x){
                swap(pre, cur);
                pre = pre->next;
            }
            cur = cur->next;
        }
        return head;
    }
};

当然,还有一种做法就是:把小于x的节点都连起来,把不小于x的节点也都连起来,再拼接在一起。这种做法就保持了原链表里的相对顺序。正如下面这题的做法。

86、分隔链表

在这里插入图片描述
其实,如果先做这题的话,再做上面那道题,就没那么迷了。这题也比上一道题的要求稍微高一点,就是要保持原链表里的相对顺序。

这里也是使用双指针before和after来追踪上述的两个链表。两个指针用于创建两个链表,一个用于保存原链表中值 < x的元素;另一个用于保存原链表中值 > x的元素。最后将after拼接在before的后面。before_head、after_head是两个链表的头结点。

具体来看:
这里使用LeetCode官方题解的图
1、初始化两个指针 before 和 after。在实现中,将两个指针初始化为哑 ListNode,这有助于减少条件判断。
在这里插入图片描述

2、利用head指针遍历原链表。

3、若head指针指向的元素值 < x,该节点应当是before链表的一部分。因此,将其移到before中。
在这里插入图片描述
4、否则,该节点应当是after链表的一部分。因此,将其移到after中。
在这里插入图片描述

5、遍历完原有链表的全部元素之后,我们得到了两个链表 before 和 after。原有链表的元素或者在before 中或者在 after 中,这取决于它们的值。
在这里插入图片描述
6、现在,将after接在before后面,组成所求的链表。由于从左到右遍历原链表,故两个链表中元素的相对顺序不会发生改变。
在这里插入图片描述
注:为了算法实现更容易,我们使用了哑结点初始化。不能让哑结点成为返回链表中的一部分,因此在组合两个链表时需要向前移动一个节点。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

typedef struct ListNode ListNode;
struct ListNode* partition(struct ListNode* head, int x){
    if(head == NULL || head->next == NULL)  return head;
    ListNode* before_head = (ListNode*)malloc(sizeof(ListNode));
    before_head->val = 0;
    ListNode* before = before_head;
    ListNode* after_head = (ListNode*)malloc(sizeof(ListNode));
    after_head->val = 0;
    ListNode* after = after_head;
    ListNode* p = head;
    while(p){
        if(p->val < x){
            before->next = p;
            before = before->next;
        }
        else{
            after->next = p;
            after = after->next;
        }
        p = p->next;
    }
    after->next = NULL;
    before->next = after_head->next;
   
    return before_head->next;
}

复杂度分析

时间复杂度: O(N),其中N是原链表的长度,对该链表进行了遍历。

空间复杂度: O(1),只移动了原有的结点,因此没有使用任何额外空间。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值