zoukankan      html  css  js  c++  java
  • 排序链表

    在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。

    示例 1:

    输入: 4->2->1->3
    输出: 1->2->3->4
    示例 2:

    输入: -1->5->3->4->0
    输出: -1->0->3->4->5

    递归版:(不符合空间复杂度要求)

    题目要求时间空间复杂度分别为O(nlogn)O(nlogn)和O(1)O(1),根据时间复杂度我们自然想到二分法,从而联想到归并排序;

    对数组做归并排序的空间复杂度为 O(n),分别由新开辟数组O(n)和递归函数调用O(logn)组成,而根据链表特性

    数组额外空间:链表可以通过修改引用来更改节点顺序,无需像数组一样开辟额外空间;
    递归额外空间:递归调用函数将带来O(logn)的空间复杂度,因此若希望达到O(1)空间复杂度,则不能使用递归
    通过递归实现链表归并排序,有以下两个环节:

    分割 cut 环节: 找到当前链表中点,并从中点将链表断开(以便在下次递归 cut 时,链表片段拥有正确边界);
    我们使用 fast,slow 快慢双指针法,奇数个节点找到中点,偶数个节点找到中心左边的节点。
    找到中点 slow 后,执行 slow.next = None 将链表切断。
    递归分割时,输入当前链表左端点 head 和中心节点 slow 的下一个节点 tmp(因为链表是从 slow 切断的)。
    cut 递归终止条件: 当head.next == None时,说明只有一个节点了,直接返回此节点。
    合并 merge 环节: 将两个排序链表合并,转化为一个排序链表。
    双指针法合并,建立辅助ListNode h 作为头部。
    设置两指针 left, right 分别指向两链表头部,比较两指针处节点值大小,由小到大加入合并链表头部,指针交替前进,直至添加完两个链表。
    返回辅助ListNode h 作为头部的下个节点 h.next。
    时间复杂度 O(l + r),l, r 分别代表两个链表长度。
    当题目输入的 head == None 时,直接返回None。

     1 /**
     2  * Definition for singly-linked list.
     3  * struct ListNode {
     4  *     int val;
     5  *     ListNode *next;
     6  *     ListNode(int x) : val(x), next(NULL) {}
     7  * };
     8  */
     9 class Solution {
    10 public:
    11     ListNode* sortList(ListNode* head) {
    12         if (head == nullptr || head->next == nullptr)
    13             return head;
    14         ListNode *fast = head->next, *slow = head;
    15         //快慢指针找到链表中点
    16         while (fast!=nullptr&&fast->next!=nullptr)
    17         {
    18             slow = slow->next;
    19             fast = fast->next->next;
    20         }
    21         //cut链表
    22         ListNode *tmp = slow->next;
    23         slow->next = nullptr;
    24 
    25         ListNode *left = sortList(head);
    26         ListNode *right = sortList(tmp);
    27 
    28         ListNode *h = new ListNode(0);
    29         ListNode *res = h;
    30         while (left!=nullptr&&right!=nullptr)
    31         {
    32             if (left->val < right->val)
    33             {
    34                 h->next = left;
    35                 left = left->next;
    36             }
    37             else
    38             {
    39                 h->next = right;
    40                 right = right->next;
    41             }
    42             h = h->next;
    43         }
    44         h->next = left != nullptr ? left : right;
    45         return res->next;
    46     }
    47 };

    非递归版:(由下往上处理)

     1 class Solution {
     2 public:
     3     ListNode* sortList(ListNode* head) {
     4         ListNode dummyHead(0);
     5         dummyHead.next = head;
     6         auto p = head;
     7         int length = 0;
     8         while (p) {
     9             ++length;
    10             p = p->next;
    11         }
    12         
    13         for (int size = 1; size < length; size <<= 1) {
    14             auto cur = dummyHead.next;
    15             auto tail = &dummyHead;
    16             
    17             while (cur) {
    18                 auto left = cur;
    19                 auto right = cut(left, size); // left->@->@ right->@->@->@...
    20                 cur = cut(right, size); // left->@->@ right->@->@  cur->@->...
    21                 
    22                 tail->next = merge(left, right);
    23                 while (tail->next) {
    24                     tail = tail->next;
    25                 }
    26             }
    27         }
    28         return dummyHead.next;
    29     }
    30     
    31     ListNode* cut(ListNode* head, int n) {
    32         auto p = head;
    33         while (--n && p) {
    34             p = p->next;
    35         }
    36         
    37         if (!p) return nullptr;
    38         
    39         auto next = p->next;
    40         p->next = nullptr;
    41         return next;
    42     }
    43     
    44     ListNode* merge(ListNode* l1, ListNode* l2) {
    45         ListNode dummyHead(0);
    46         auto p = &dummyHead;
    47         while (l1 && l2) {
    48             if (l1->val < l2->val) {
    49                 p->next = l1;
    50                 p = l1;
    51                 l1 = l1->next;       
    52             } else {
    53                 p->next = l2;
    54                 p = l2;
    55                 l2 = l2->next;
    56             }
    57         }
    58         p->next = l1 ? l1 : l2;
    59         return dummyHead.next;
    60     }
    61 };
  • 相关阅读:
    java web使用WebSocket
    solr的使用
    mybatis中模糊查询的实现方式
    Java反射的简单使用
    TCP/IP协议 资料整理
    Java单向链表的实现
    Spring boot使用JWT来做接口登录验证
    sql性能优化
    前端实践项目(四)使用koa搭建开发环境
    前端实践项目 目录
  • 原文地址:https://www.cnblogs.com/wangshaowei/p/11383539.html
Copyright © 2011-2022 走看看