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结点很多时候可以方便操作简化代码。

posted on 2014-08-16 15:58  Ryan-Xing  阅读(197)  评论(0编辑  收藏  举报