0
点赞
收藏
分享

微信扫一扫

LeetCode - 解题笔记 - 148 - Sort List

兽怪海北 2022-03-21 阅读 28

Solution 1

要求线性对数时间复杂度,那只能是归并或者快速排序(其他排序链表实现太难不考虑了),再加之快速排序的调换次数过多,实在不好处理(且对链表实际的复杂度会更高)且不稳定(最坏情况下是 O ( n 2 ) O(n^2) O(n2)),因此这里只考虑归并排序。整体思路如下:

  1. 找到中点,然后分支(快慢指针,参考 0143. Reorder List
  2. 在分支内,完成进一步分支的排序
  3. 两个分支完成内部排序之后,按顺序归并(合并链表 0021. Merge Two Sorted Lists )

这里面有一个两个小调整,一个是中点的部分,原有的实现会在偶数情况下取左侧那个,因此不方便就重新实现一下;另一个是合并的部分,判断逻辑有点多余,使用假head进行合并。

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n为输入链表的节点个数,标准归并排序实现
  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n为输入链表的节点个数,函数递归调用占用
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == nullptr) {
            return head;
        }
        
        return this->sortList(head, nullptr);
    }
    
private:
    ListNode* sortList(ListNode* head, ListNode* tail) {
        // head是当前head,tail是尾节点的next
        if (head == nullptr) {
            return head;
        }
        
        if (head->next == tail) {
            // 子链表就一个节点
            head->next = nullptr;
            return head;
        }

        auto slow = head, fast = head;
        while (fast != tail) {
            slow = slow->next;
            fast = fast->next;
            if (fast != tail) {
                fast = fast->next;
            }
        }

        auto mid = slow;
        
        return this->merge(this->sortList(head, mid), this->sortList(mid, tail));
    }
    
    ListNode* merge(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr && l2 == nullptr) {
            return nullptr;
        }
        
        if (l1 == nullptr) {
            return l2;
        }
        if (l2 == nullptr) {
            return l1;
        }
        
        auto ans = new ListNode();
        
        auto cur = ans;
        while(l1 != nullptr && l2 != nullptr) {
            if (l1->val <= l2->val) {
                cur->next = l1;
                l1 = l1->next;
            }
            else {
                cur->next = l2;
                l2 = l2->next;
            }
            cur = cur->next;
        }
        
        if (l1 != nullptr) {
            cur->next = l1;
        }
        else {
            cur->next = l2;
        }
        
        return ans->next;
    }

};

Solution 2

然后我发现有递归调用,不是 O ( 1 ) O(1) O(1)的空间复杂度……

那就得用while循环替代递归了,整体就是从长度1开始,逐渐二倍扩展,对当前小分段内部的进行合并(仅一层递归)。需要额外处理第二个分段可能为空的情形。

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n为输入链表的节点个数,标准归并排序实现
  • 空间复杂度: O ( 1 ) O(1) O(1),由于while中的调用每次仅一层递归,因此为常数规模的空间复杂度
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* sortList(ListNode* head) {
        if (head == nullptr) {
            return head;
        }

        // 确定length
        int length = 0;
        auto temp = head;
        while (temp != nullptr) {
            length++;
            temp = temp->next;
        }
        
        auto ans = new ListNode();
        ans->next = head;
        
        for (int subLength = 1; subLength < length; subLength *= 2) {
            auto prev = ans, cur = ans->next;
            while (cur != nullptr) {
                // 第一个小分段
                auto tmp1 = cur;
                for (int i = 1; i < subLength && cur->next != nullptr; i++) {
                    cur = cur->next;
                }
                
                // 第二个小分段,需要注意
                auto tmp2 = cur->next;
                cur->next = nullptr; // 提取第一个分段
                cur = tmp2; // 如果为nullptr,就直接跳过(子序列保证有序)
                if (cur != nullptr) {
                    for (int i = 1; i < subLength && cur->next != nullptr; i++) {
                        cur = cur->next;
                    }
                }
                
                
                ListNode *nextTmp1 = nullptr; // 下一轮第一个分段的头
                if (cur != nullptr) {
                    nextTmp1 = cur->next;
                    cur->next = nullptr; // 投递第二个分段
                }
                
                auto mergedTmp = this->merge(tmp1, tmp2);
                prev->next = mergedTmp;
                
                while (prev->next != nullptr) {
                    prev = prev->next; // 下一轮的prev就是第二段的最后一个(或者第二段为空时的第一段最后一个)
                }
                cur = nextTmp1; // 下一轮
            }
        }
        
        return ans->next;
    }
    
private:
    ListNode* merge(ListNode* l1, ListNode* l2) {
        if (l1 == nullptr && l2 == nullptr) {
            return nullptr;
        }
        
        if (l1 == nullptr) {
            return l2;
        }
        if (l2 == nullptr) {
            return l1;
        }
        
        auto ans = new ListNode();
        
        auto cur = ans;
        while(l1 != nullptr && l2 != nullptr) {
            if (l1->val <= l2->val) {
                cur->next = l1;
                l1 = l1->next;
            }
            else {
                cur->next = l2;
                l2 = l2->next;
            }
            cur = cur->next;
        }
        
        if (l1 != nullptr) {
            cur->next = l1;
        }
        else {
            cur->next = l2;
        }
        
        return ans->next;
    }

};

Solution 3

Solution 1的Python实现

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None: return head
        
        return self.__sortList(head, None)
        
    def __sortList(self, head: Optional[ListNode], tail: Optional[ListNode]) -> Optional[ListNode]:
        if head is None: return head
        
        if head.next == tail:
            head.next = None
            return head
        
        slow, fast = head, head
        while fast != tail:
            slow = slow.next
            fast = fast.next
            if fast != tail: fast = fast.next
                
        mid = slow
        
        return self.__merge(self.__sortList(head, mid), self.__sortList(mid, tail))
        
    def __merge(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        if l1 is None and l2 is None: return None
        
        if l1 is None: return l2
        if l2 is None: return l1
        
        ans = ListNode()
        
        cur = ans
        while l1 is not None and l2 is not None:
            if l1.val <= l2.val:
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
                
            cur = cur.next
            
        if l1 is not None: cur.next = l1
        else: cur.next = l2
            
        return ans.next

Solution 4

Solution 2的Python实现

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]:
        if head is None: return head
        
        length = 0
        temp = head
        while temp is not None:
            length += 1
            temp = temp.next
            
        ans = ListNode()
        ans.next = head
    
        subLength = 1
        while subLength < length:
            prev = ans
            cur = ans.next
            while cur is not None:
                tmp1 = cur
                for i in range (1, subLength):
                    if cur.next is not None:
                        cur = cur.next
                    else: break
                        
                tmp2 = cur.next
                cur.next = None
                cur = tmp2
                if cur is not None:
                    for i in range(1, subLength):
                        if cur.next is not None:
                            cur = cur.next
                        else: break
                            
                nextTmp1 = None
                if cur is not None:
                    nextTmp1 = cur.next
                    cur.next = None
                    
                mergedTmp = self.__merge(tmp1, tmp2)
                prev.next = mergedTmp
                
                while prev.next is not None: prev = prev.next
                    
                cur = nextTmp1
            
            subLength *= 2
            
        return ans.next
        
    def __merge(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
        if l1 is None and l2 is None: return None
        
        if l1 is None: return l2
        if l2 is None: return l1
        
        ans = ListNode()
        
        cur = ans
        while l1 is not None and l2 is not None:
            if l1.val <= l2.val:
                cur.next = l1
                l1 = l1.next
            else:
                cur.next = l2
                l2 = l2.next
                
            cur = cur.next
            
        if l1 is not None: cur.next = l1
        else: cur.next = l2
            
        return ans.next
举报

相关推荐

0 条评论