首页 > 代码库 > Partition List

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.

For example,
Given 1->4->3->2->5->2 and x = 3,
return 1->2->2->4->3->5.  

分析:《Introductin to Alogrithims》讲解quick sort是给出了一种partition array的方法,但是这种方法用在这道题上不好,原因有二。第一,partition array的方法不能preserve the original relative order。第二,partition array中是两个元素不断互换,对于链表来说我们可以采用更高效的方法。在这里,我们定义几个指针,index指向大于等于x的结点段(这个结点段指第一个大于等于x的结点到p之前的结点),p指向当前遍历到的结点,pre_p指向p前一个结点。在partition的时候如果p->val小于x我们只要将p移动到index后面即可(这里的移动包含几个操作,比如处理pre_p->next, p->next)。具体实现时,有两个方面要注意,一是如果p移动到index后面后,遍历的指针应该指向p移动前的next;二是如果index后面是p,即index = pre_p时,操作跟index!=pre_p不同。算法时间复杂度是O(n),空间复杂度是O(1)。代码如下:

 1 class Solution { 2 public: 3     ListNode *partition(ListNode *head, int x) { 4         ListNode * dummy = new ListNode(-1); 5         dummy->next = head; 6         ListNode * index = dummy; 7         ListNode * p = head, * pre_p = dummy; 8         while(p){ 9             if(p->val < x){10                 if(pre_p != index){11                     pre_p->next = p->next;12                     p->next = index->next;13                     index->next = p;14                 }else pre_p = p;15                 index = index->next;16                 p = pre_p->next;17             }else{18                 pre_p = p;19                 p = p->next;20             }21         }22         return dummy->next;23     }24 };

出上面的方法外,还有一种更好理解的方法,操作也更简便,我们可以设两个虚拟结点,然后一个虚拟结点后是小于x的结点,另一个虚拟结点后是大于等于x的结点。时间复杂度和空间复杂度亦为O(n)和O(1)。

 1 class Solution { 2 public: 3 ListNode* partition(ListNode* head, int x) { 4 ListNode left_dummy(-1); // 头结点 5 ListNode right_dummy(-1); // 头结点 6 auto left_cur = &left_dummy; 7 auto right_cur = &right_dummy; 8 for (ListNode *cur = head; cur; cur = cur->next) { 9 if (cur->val < x) {10 left_cur->next = cur;11 left_cur = cur;12 } else {13 right_cur->next = cur;14 right_cur = cur;15 }16 }17 left_cur->next = right_dummy.next;18 right_cur->next = nullptr;19 return left_dummy.next;20 }21 };

Note:在链表头部加一个dummy结点很多时候可以方便操作简化代码。