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;