L9.【LeetCode题解】分割链表(三种方法)

目录

1.题目

2.自解

提交结果

3.其他解法

方法1:开辟一个新链表

提交结果

方法2:不开辟额外的空间

提交结果


1.题目

面试题 02.04. 分割链表

 

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你不需要 保留 每个分区中各节点的初始相对位置。

示例 1:

a0d2d83a0e677b81f4280b2d3f91a957.jpeg

输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]

示例 2:

输入:head = [2,1], x = 2
输出:[1,2]

提示:

  • 链表中节点的数目在范围 [0, 200]
  • -100 <= Node.val <= 100
  • -200 <= x <= 200
  • 代码模版
  • /**
     * Definition for singly-linked list.
     * struct ListNode {
     *     int val;
     *     struct ListNode *next;
     * };
     */
    struct ListNode* partition(struct ListNode* head, int x) 
    {
        
    }

★注:示例1画的图其实是错的,最后的结果应该是1->2->2->3->4->5

2.自解

算法:开辟两个带哨兵位的新链表进行尾插,比x小的放到一个链表,比x大的放到另外一个链表,最后将这两个链表与x合并为一个链表,返回头节点的地址.为了避免尾插时找尾,为两个链表定义各自的尾指针

本题使用带哨兵位的头节点,防止没有一个数字比x大或没有一个数字比x小出现,导致某个链表为空

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* partition(struct ListNode* head, int x) 
{
    struct ListNode* cur=head;
    struct ListNode* p1guard=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* p2guard=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode* p1tail=p1guard;
    struct ListNode* p2tail=p2guard;
    while(cur)
    {
        if (cur->val<x)
        {
            struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
            newnode->val=cur->val;
            p1tail->next=newnode;
            p1tail=newnode;
        }
        else
        {
            struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
            newnode->val=cur->val;
            p2tail->next=newnode;
            p2tail=newnode; 
        }
        cur=cur->next;
    }
    p1tail->next=p2tail->next=NULL;//不置空会导致野指针行为,这个非常关键
    if (p1tail==p1guard)//一个小于x的都没有
        return p2guard->next;
    if (p2tail==p2guard)//一个大于等于x的都没有
        return p1guard->next;
    p1tail->next=p2guard->next;
    return p1guard->next;
}

可以不用判断节点是否开辟成功,最后也不用free 

提交结果

3.其他解法

方法1:开辟一个新链表

算法:只开辟一个带哨兵位的新链表,小于x的头插,大于等于x的尾插

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* partition(struct ListNode* head, int x) 
{
    struct ListNode* cur=head;
    struct ListNode* p1guard=(struct ListNode*)malloc(sizeof(struct ListNode));
    p1guard->next=NULL;
    struct ListNode* p1tail=p1guard;
    while(cur)
    {
        if (cur->val<x)
        {
           if (p1tail==p1guard)//只有哨兵位,尾插
           {
                struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
                newnode->val=cur->val;
                p1guard->next=newnode;
                p1tail=newnode;
           }
           else
           {
                struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
                newnode->val=cur->val;
                newnode->next=p1guard->next;
                p1guard->next=newnode;                
           }
        }
        else
        {
            struct ListNode* newnode=(struct ListNode*)malloc(sizeof(struct ListNode));
            newnode->val=cur->val;
            p1tail->next=newnode;
            p1tail=newnode;
        }
        cur=cur->next;
    }
    p1tail->next=NULL;//不置空会导致野指针行为,这个非常关键
    return p1guard->next;
}

可以不用判断节点是否开辟成功,最后也不用free  

提交结果

方法2:不开辟额外的空间

线索:"小于 x 的节点都出现在 大于或等于 x 的节点之前"显然是数据分块问题,可以在空间的基础上使用双指针

算法:设双指针p1和p2都从head出发,由于要遵循:"小于 x 的节点都出现在 大于或等于 x 的节点之前",因此就要通过交换两个指针指向的值来让大于或等于x的值翻到后面去

设p1找大值,p2找小值,注意:一开始要让p1和p2都要指向同一个节点,且节点的值大于或等于x,这样后面才容易换,之后p2先出发找小,与p1交换才能让大于或等于x的值翻到后面去,小于x的值翻到前面去(注意循环时p1和p2都不能为空!)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* partition(struct ListNode* head, int x) 
{
    if(head == NULL)
        return head;

    struct ListNode* p1 = head;
    struct ListNode* p2 = head;
    
    while(p1 != NULL && p1->val < x)
    {
        p1 = p1->next;
    }

    while(p1 != NULL)
    {
        while(p2 != NULL && p2->val < x)
        {
            p2 = p2->next;
        }
        while(p1 != NULL && p1->val >= x)
        {
            p1 = p1->next;
        }
        if(p2 != NULL && p1 != NULL)
        {
            int tmp=p2->val;
            p2->val=p1->val;
            p1->val=tmp;
        }
    }
    return head;
}

提交结果

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhangcoder

赠人玫瑰手有余香,感谢支持~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值