leetcode 148 题 排序链表

分治的思想,先分治,把数据结构不断对半分,直到最小单位,然后开始排序,再组合,递归实现。

这个题目是要把乱序的链表排成升序。由于链表的特殊结构,操作会有点复杂,不过也有比较好的方法。

  1. 分治 首先就是把大问题变成多个小问题,这里我们可以一直把链表对半分组。这里涉及 leetcode 876 题,找出链表的中间节点。用这个思路来把大问题化为多个小问题。
  2. 排列组合 第二件事就是排列组合了,把小问题排列组合成大一点的问题。这里涉及 leetcode 21 题 按顺序合并两个链表。

如此一来,一道中等难度的排序链表问题,能通过两道简单的链表查找和组合问题解决。

下面是代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
// 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) {
    // 递归
        ListNode* sorted = mergeSort(head);
        return sorted;
    }

    ListNode* merge(ListNode* l1, ListNode* l2) {
    // 这是合并链表的
    // 虚拟指针作头节点
    // 这里不用new的方式创建dummy指针,后续提交能节省20MB左右的内存。
        ListNode dummy(0);
        ListNode* tail = &dummy;
        // 开始合并
        while (l1 && l2) {
            if (l1->val < l2->val) {
                tail->next = l1;
                l1 = l1->next;
            } else {
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
        }
// 一个链表空了,把另外剩下的链表直接接上。
        if (l1) {
            tail->next = l1;
        } else if (l2) {
            tail->next = l2;
        }
// 返回虚拟节点的下一个节点作为头节点。
        return dummy.next;
    }

    ListNode* mergeSort(ListNode* head) {
// 这是快慢指针查找中间节点
        if (!head || !head->next) {
            return head;
        }
// 设定快慢指针
        ListNode* slow = head;
        ListNode* fast = head->next;
// 循环遍历
        while (fast && fast->next) {
            slow = slow->next;
            fast = fast->next->next;
        }
// 断开
        ListNode* mid = slow->next;
        slow->next = NULL;
        // 断开后的两边链表再分别递归找中点然后断开。
        ListNode* left = mergeSort(head);
        ListNode* right = mergeSort(mid);
        // 返回的两个链表按顺序拼接。
        return merge(left, right);
    }
};

有个需要注意的点:
mergeSort 这个函数是用来找中点的,其中快指针是 head->next 这是为了让找到的中点为偶数中间两个的前一个,如果只是 head 的话,将会是中间的后一个。
如果是 876 题,是不能用这里的方式的,876 题求的是中间的后一个。

Icarus安装

前言

通过前面的文章,已经学习了 Hexo 博客的安装和基本操作。本篇将解决主题的安装问题。

Hexo 有不少的主题可以挑选,官网的 主题页面 有 300+ 的主题可供选择。

阅读更多

Hexo安装

Hexo

是什么

Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用  Markdown(或其他渲染引擎)解析文章,在几秒内,即可利用靓丽的主题生成静态网页。

安装

阅读更多

C++ 11

auto

  • 使用 auto 必须初始化;
  • auto 根据初始化的值来推导数据类型;
  • 当类型不为引用时,auto 的推导结果将不保留表达式的 const 属性;
  • 当类型为引用时,auto 的推导结果将保留表达式的 const 属性。
阅读更多

static关键字

全局变量

static 声明全局变量,不改变全局变量的存储位置与生命周期,仅改变全局变量的作用域,不被其他源文件通过 extern 调用。

阅读更多

Lambda表达式

Lambda 表达式

能够捕获作用域中的变量的无名函数对象。

基本语法

1
[capture] (parameters) mutable -> return-type {statement}
阅读更多

右值引用

左值

左值可以被看作一个具有名称的内存位置。

阅读更多

虚函数和纯虚函数

虚函数和纯虚函数

定义

虚函数

类中,声明函数前有virtual关键字的为虚函数

阅读更多