其他分享
首页 > 其他分享> > leetcode 148 排序链表

leetcode 148 排序链表

作者:互联网

有点难的题目,因为没有想到归并排序的思想。简单来说就是不断的对半分割,然后递归的完成两个分块的排序之后,再将这两个排好序的分块按序合并,就完成了排序。先贴一种自顶向下的方法。这种方法的细节之处在于不断的分割过程中,对只剩两个元素的情况进行处理,删去第二个元素,也就是将头结点的next指针设为null。而这种方法的依据在于分割的过程中存在重复的元素,比如3个元素的单元会被分为两个2元素的单元,第一个单元继承原始单元的第一个元素,第二个则继承第二个,第三个不用管,因为这是分割前另外一块的开头。贴代码

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode() : val(0), next(nullptr) {}
 7  *     ListNode(int x) : val(x), next(nullptr) {}
 8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 9  * };
10  */
11 class Solution {
12 public:
13     ListNode* sortList(ListNode* head) 
14     {
15         return sort(head,nullptr);                
16     }
17     ListNode* sort(ListNode* head,ListNode* tail)
18     {
19         if(!head)
20         return nullptr;
21         //
22         if(head->next == tail)
23         {
24             head->next = nullptr;
25             return head;
26         }
27         //分
28         ListNode* pointer_1 = head;
29         ListNode* pointer_2 = head;
30         while(pointer_2!=tail)
31         {
32             pointer_1 = pointer_1->next;
33             pointer_2 = pointer_2->next;
34             if(pointer_2!=tail)
35             pointer_2 = pointer_2->next;
36         }
37         ListNode* mid = pointer_1;
38         //分割时存在重叠部分,而这一部分会在分割到两个元素时被舍去,很巧妙的设计
39         ListNode* head_1 = sort(head,mid);
40         ListNode* head_2 = sort(mid,tail);
41         return merge(head_1,head_2);        
42     }
43     ListNode* merge(ListNode* head_1,ListNode* head_2)
44     {
45         ListNode* head = new ListNode(0);
46         ListNode* temp = head;
47         ListNode* temp_1 = head_1;
48         ListNode* temp_2 = head_2;
49         while(temp_1!=nullptr && temp_2!=nullptr)
50         {
51             if(temp_1->val > temp_2->val)
52             {
53                 temp->next = temp_2;
54                 temp_2 = temp_2->next;
55             }
56             else
57             {
58                 temp->next = temp_1;
59                 temp_1 = temp_1->next;
60             }
61             temp = temp->next;
62         }
63         if(temp_1)
64         temp->next = temp_1;
65         else if(temp_2)
66         temp->next = temp_2;
67         return head->next;
68     }
69 };

 修改了下分割时无重叠的方法,几个小细节改一下,贴代码

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode() : val(0), next(nullptr) {}
 7  *     ListNode(int x) : val(x), next(nullptr) {}
 8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 9  * };
10  */
11 class Solution {
12 public:
13     ListNode* sortList(ListNode* head) 
14     {
15         if(!head)
16         return head;
17         ListNode* end = head;
18         while(end->next)
19         end = end->next;
20         return sort(head,end);                
21     }
22     ListNode* sort(ListNode* head,ListNode* tail)
23     {
24         if(head == nullptr)
25         return nullptr;
26         if(head == tail)
27         {
28             head->next = nullptr;
29             return head;
30         }
31         //分
32         ListNode* pointer_1 = head;
33         ListNode* pointer_2 = head;
34         while(pointer_2!=tail)
35         {
36             //由于分割时不存在重叠部分,于是只有在快指针能够推两次的情况下慢指针才会推一次
37             //为了两个元素时能够分割正确
38             pointer_2 = pointer_2->next;
39             if(pointer_2!=tail)
40             {
41                 pointer_1 = pointer_1->next;
42                 pointer_2 = pointer_2->next;
43             }
44         }
45         //cout<<pointer_1->next->val<<endl;
46         //cout<<pointer_2->val<<endl;
47         ListNode* mid = pointer_1->next;
48         //分割时不存在重叠部分
49         ListNode* head_1 = sort(head,pointer_1);
50         ListNode* head_2 = sort(mid,pointer_2);
51         //cout<<head_1->val<<endl;
52         return merge(head_1,head_2);        
53     }
54     ListNode* merge(ListNode* head_1,ListNode* head_2)
55     {
56         ListNode* head = new ListNode(0);
57         ListNode* temp = head;
58         ListNode* temp_1 = head_1;
59         ListNode* temp_2 = head_2;
60         while(temp_1!=nullptr && temp_2!=nullptr)
61         {
62             if(temp_1->val > temp_2->val)
63             {
64                 temp->next = temp_2;
65                 temp_2 = temp_2->next;
66             }
67             else
68             {
69                 temp->next = temp_1;
70                 temp_1 = temp_1->next;
71             }
72             temp = temp->next;
73             //cout<<temp->val<<endl;
74         }
75         if(temp_1)
76         temp->next = temp_1;
77         else if(temp_2)
78         temp->next = temp_2;
79         return head->next;
80     }
81 };

除了上述的自顶向下的方法,还有自下向顶的方法,首选以每个节点为单位进行两个两个的排序,以这种方式完成第一轮排序之后,就进行循环,将上述的子串的大小加倍,将两个各自完成排序的子串进行归并排序,以此类推,能够完成整个串的排序。代码的撰写中细节主要在于找到两个子串的头以及将子串分隔开。尤其是第二个子串,可能会出现元素不足甚至就没有元素的情况,所以需要单独的取出进行讨论。

 1 /**
 2  * Definition for singly-linked list.
 3  * struct ListNode {
 4  *     int val;
 5  *     ListNode *next;
 6  *     ListNode() : val(0), next(nullptr) {}
 7  *     ListNode(int x) : val(x), next(nullptr) {}
 8  *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 9  * };
10  */
11 class Solution {
12 public:
13     ListNode* sortList(ListNode* head) 
14     {
15         if(!head)
16         return nullptr;
17         int length = 0;
18         ListNode* listSize = head;
19         while(listSize!=nullptr)
20         {
21             length++;
22             listSize = listSize->next;
23         }
24         //将newHead的next节点赋为head主要是为了之后的循环变量temp的使用
25         ListNode* newHead = new ListNode(0,head);
26         for(int subLength = 1 ; subLength < length ; subLength*=2)
27         {
28             ListNode* preHead = newHead;
29             ListNode* temp = newHead->next;
30             while(temp!=nullptr)
31             {
32                 //找到第一个head
33                 ListNode* head_1 = temp;
34                 for(int i = 1 ; i < subLength && temp->next!=nullptr ; i++)
35                 temp = temp->next;
36                 ListNode* head_2 = temp->next;
37                 temp->next = nullptr;
38                 temp = head_2;
39                 //找到第二个head
40                 for(int i = 1 ; i < subLength && temp!=nullptr &&  temp->next!=nullptr ; i++)
41                 temp = temp->next;
42                 ListNode* end = nullptr;
43                 //判断第二个部分中是否有元素,如果有,则将temp的next元素脱钩
44                 //如果无元素,则无需脱钩
45                 if(temp!=nullptr)
46                 {
47                     end = temp->next;
48                     temp->next = nullptr;
49                 }
50                 //合并
51                 ListNode* merged = merge(head_1,head_2);
52                 preHead->next = merged;
53                 while(preHead->next!=nullptr)
54                 preHead = preHead->next;
55                 temp = end;
56             }
57         }
58         return newHead->next;               
59     }
60     ListNode* merge(ListNode* head_1,ListNode* head_2)
61     {
62         ListNode* head = new ListNode(0);
63         ListNode* temp = head;
64         ListNode* temp_1 = head_1;
65         ListNode* temp_2 = head_2;
66         while(temp_1!=nullptr && temp_2!=nullptr)
67         {
68             if(temp_1->val > temp_2->val)
69             {
70                 temp->next = temp_2;
71                 temp_2 = temp_2->next;
72             }
73             else
74             {
75                 temp->next = temp_1;
76                 temp_1 = temp_1->next;
77             }
78             temp = temp->next;
79             //cout<<temp->val<<endl;
80         }
81         if(temp_1)
82         temp->next = temp_1;
83         else if(temp_2)
84         temp->next = temp_2;
85         return head->next;
86     }
87 };

 

标签:head,ListNode,temp,nullptr,148,next,链表,pointer,leetcode
来源: https://www.cnblogs.com/zhaohhhh/p/15499021.html