​LeetCode刷题实战148:排序链表

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 排序链表,我们先来看题面:

https://leetcode-cn.com/problems/sort-list/

Given the head of a linked list, return the list after sorting it in ascending order.

Follow up: Can you sort the linked list in O(n logn) time and O(1) memory (i.e. constant space)?

题意

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

进阶:

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

样例

解题

https://blog.csdn.net/qq_41855420/article/details/87901524

解题思路:

思路分析:由于题目特意要求 O(n log n) 时间复杂度和常数级空间复杂度 所以不能使用冒泡、计数排序啥的,比较符合要求的就是归并排序。

归并排序:排序一段序列分为排序前部分、后部分,再合并两个已经排序好的部分。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 * int val;
 * ListNode *next;
 * ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
  ListNode* sortList(ListNode* head) {
    if (head == NULL || head->next == NULL) {
      return head;
    }
    ListNode *end = head;//定位到链表的尾部
    while (end != NULL && end->next != NULL) {
      end = end->next;
    }
    return mergeSort(head, end);
  }
  //归并排序
  ListNode* mergeSort(ListNode* head, ListNode *end) {
    if (head == end) {//这段链表只有一个节点
      return head;
    }
    if (head->next == end) {//只有两个节点
      if (head->val > end->val) {
        int tempVaule = head->val;
        head->val = end->val;
        end->val = tempVaule;
      }
      return head;
    }
        //快慢指针,定位链表中间
    ListNode *slowPtr = head, *fastPtr = head;
    while (fastPtr != end) {
      slowPtr = slowPtr->next;//慢指针走一步
      fastPtr = fastPtr->next;//快指针走两步
      if (fastPtr != end) {
        fastPtr = fastPtr->next;//快指针走两步
      }
    }
        
    //第一步 递归,排序右半
    ListNode * rightList = mergeSort(slowPtr->next, end);
    slowPtr->next = NULL;//将左右两部分切开
    //第二步 递归,排序左半
    ListNode * leftList = mergeSort(head, slowPtr);
        
    //第三步 合并
    ListNode *pHead = NULL, *pEnd = NULL;//合并链表的头、尾
    if (rightList == NULL) {
      return leftList;
    }
    //初始化头结点、尾节点
    if (rightList->val > leftList->val) {
      pEnd = pHead = leftList;
      leftList = leftList->next;
    }
    else {
      pEnd = pHead = rightList;
      rightList = rightList->next;
    }
    //合并,每次将较小值放入新链表
    while (rightList && leftList) {
      if (rightList->val > leftList->val) {
        pEnd->next = leftList;
        pEnd = pEnd->next;
        leftList = leftList->next;
      }
      else {
        pEnd->next = rightList;
        pEnd = pEnd->next;
        rightList = rightList->next;
      }
    }
    //可能某个链表有剩余
    if (rightList == NULL) {
      pEnd->next = leftList;
    }
    else {
      pEnd->next = rightList;
    }
    return pHead;
  }
};

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力。

上期推文:

LeetCode1-140题汇总,希望对你有点帮助!

LeetCode刷题实战141:环形链表

LeetCode刷题实战142:环形链表 II

LeetCode刷题实战143:重排链表

LeetCode刷题实战144:二叉树的前序遍历

LeetCode刷题实战145:二叉树的后序遍历

LeetCode刷题实战146:LRU 缓存机制

LeetCode刷题实战147:对链表进行插入排序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值