LeetCode 86. Partition List(分隔链表)--c语言

 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

解题思路:

设置两个头结点after_head和before_head用于大于等于x的结点和小于x的结点,收集完毕之后再将after_head的链表链接到before_head的链表之后实现分隔

/*
执行用时 : 0 ms, 在Partition List的C提交中击败了100.00% 的用户
内存消耗 : 7.3 MB, 在Partition List的C提交中击败了6.94% 的用户
*/
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */

struct ListNode* partition(struct ListNode* head, int x){

    if(head == NULL || head->next == NULL){
        return head;
    }
    struct ListNode after_head = {0,NULL};
    struct ListNode before_head = {0,NULL};
    struct ListNode* after = &after_head;
    struct ListNode* before = &before_head;
    
    while(head){
        if(head->val < x){
            before->next = head;
            before = before->next;
        }
        else{
            after->next = head;
            after = after->next;
        }
        head = head->next;
    }
    
    before->next = after_head.next;//注意引用用".",after_head.next
    after->next = NULL;
    
    return before_head.next;
}//end

/*
struct ListNode after_head = {0,NULL};
struct ListNode before_head = {0,NULL};
struct ListNode after_head = {0,head};
struct ListNode before_head = {0,head};
输入:
[1,4,3,2,5,2]
1
执行结果:
内部错误
解决方法:
添加没有结点和只有一个结点的特殊情况的讨论
*/
/*
struct ListNode after_head = {0,head};
struct ListNode before_head = {0,head};
输入:
[]
0
输出:
[]
预期:
[]
提交结果:
Line 70: Char 15: runtime error: member access within misaligned address 0xbebebebebebebebe for type 'struct ListNode', which requires 8 byte alignment (ListNode.c)
0xbebebebebebebebe: note: pointer points here
<memory cannot be printed>
解决方法:
struct ListNode after_head = {0,NULL};
struct ListNode before_head = {0,NULL};
*/

设置哑结点,将链表分为小于x区,大于等于x区和待处理区,对于小于x区利用tail指针指向区尾来链接小于x的结点,对于大于等于x区直接对下一个进行处理。

/*
执行用时 : 4 ms, 在Partition List的C提交中击败了98.54% 的用户
内存消耗 : 7.3 MB, 在Partition List的C提交中击败了6.94%的用户
*/

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


struct ListNode* partition(struct ListNode* head, int x){
    
    
    struct ListNode* L = (struct ListNode*)malloc(sizeof(struct ListNode));
    L->next = head;
    struct ListNode* tail = L;//指向小于x区的尾节点,用于链接小于x的结点
    struct ListNode* p = head;//工作指针,遍历链表
    struct ListNode* t = NULL;
    
    
    while(tail->next != NULL && tail->next->val < x){//找到第一个大于等于x的结点tail指向其前驱,因为在第一个大于等于x的结点之前的结点都小于x,不需要处理
        tail = tail->next;
    }
    p = tail;//指向第一个大于等于x的结点的前驱,tail用于后面小于x结点的插入(尾插法,相对位置不能变)即tail指向小于x区的尾节点,不可写成p = tail->next;因为tail可能指向NULL,此时再访问tail->next出错
    while(p->next){
        
        if(p->next->val < x){
            //剥离当前处理结点t,并保持链表完整,方便对下一个结点进行访问处理
            t = p->next;
            p->next = t->next;
            //添加当前处理结点到小于x区末尾,成为新的尾节点
            t->next = tail->next;
            tail->next = t;
            //tail重新指向小于x区尾节点
            tail = t;
        }
        else{//结点值大于等于x时直接处理下一个结点
            p = p->next;
        }
    }
    
    return L->next;
}

/*
输入
[1,4,5,6,3,2,3,2]
6
输出
[1,6]
预期结果
[1,4,5,3,2,3,2,6]

输入
[1,4,5,6,3,2,3,2]
5
输出
[1,5,6]
预期结果
[1,4,3,2,3,2,5,6]
*/

后记:

注意添加对特殊情况的讨论;

注意struct ListNode after_head = {0,head},用after_head.next引用其变量,before_head也一样

注意p = tail不可写成p = tail->next;

点赞