题目链接:Sort List

Sort a linked list in O(n log n) time using constant space complexity.

这道题的要求是对链表进行排序,要求时间复杂度O(nlogn),并且常量空间复杂度。

排序,时间复杂度要求O(nlogn),因此需要考虑分治思路的排序:归并排序或者快排。

归并排序的空间复杂度为O(nlogn),貌似不太合适。不过,由于是对链表进行排序,无需申请空间存储,因此每次调用的时候无需申请空间,因此空间复杂度可以达到O(1)(递归开销姑且不算,或者直接迭代进行归并)。

至于快排,需要从两端往中间进行划分,因此不是十分适合单链表,不过应该仍可以实现。而且快排的最差情况是O(n2),所有这里暂时不考虑。

接下来说说归并排序吧:

  • 首先,需要找到中点,这可以利用快慢指针f和s进行查找。其中f每次走2步,s每次走1步,直到f到达链表尾,此时s刚好走到链表中间;
  • 接下来,需要在中间部分切开,切记,一定要切割开,否则左边链表无法判别结束。同时记录左边链表为l,右边链表为r;
  • 最后对l和r分布递归调用排序函数,并对其进行合并。至于递归终止条件就是传入链表为NULL或者只有1个节点。

时间复杂度:O(nlogn)

空间复杂度:O(1)(递归开销姑且不算)

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
class Solution
{
public:
    ListNode *sortList(ListNode *head)
    {
        if(head == NULL || head -> next == NULL)
            return head;
        
        ListNode *f = head -> next, *s = head;
        while(f != NULL && f -> next != NULL)
        {
            f = f -> next -> next;
            s = s -> next;
        }
        
        ListNode *l = head, *r = s -> next;
        s -> next = NULL;
        
        return mergeTwoLists(sortList(l), sortList(r));
    }

private:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        ListNode *h = new ListNode(0), *p;
        
        for(p = h; l1 != NULL && l2 != NULL; p = p -> next)
        {
            if(l1 -> val < l2 -> val)
                p -> next = l1, l1 = l1 -> next;
            else
                p -> next = l2, l2 = l2 -> next;
        }
        
        p -> next = l1 != NULL ? l1 : l2;
        
        return h -> next;
    }
};

接下来,也可以非递归进行实现:

时间复杂度:O(nlogn)

空间复杂度:O(1)

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
class Solution
{
public:
    ListNode *sortList(ListNode *head)
    {
        if(head == NULL || head -> next == NULL)
            return head;
        
        ListNode *carry, *counter[64];
        int fill = 0;
        while(head != NULL)
        {
            // 取链表首节点,同时head后移一步
            carry = head;
            head = head -> next;
            carry -> next = NULL;
            
            int i = 0;
            while(i < fill && counter[i] != NULL)
            {
                carry = mergeTwoLists(counter[i], carry);
                counter[i ++] = NULL;
            }
            swap(carry, counter[i]);
            
            if(i == fill)
                ++ fill;
        }
        
        for(int i = 1; i < fill; ++ i)
            counter[i] = mergeTwoLists(counter[i], counter[i - 1]);
        return counter[fill - 1];
    }

private:
    ListNode *mergeTwoLists(ListNode *l1, ListNode *l2)
    {
        ListNode *h = new ListNode(0), *p;
        
        for(p = h; l1 != NULL && l2 != NULL; p = p -> next)
        {
            if(l1 -> val < l2 -> val)
                p -> next = l1, l1 = l1 -> next;
            else
                p -> next = l2, l2 = l2 -> next;
        }
        
        p -> next = l1 != NULL ? l1 : l2;
        
        return h -> next;
    }
};

For example:

list is 1 -> 3 -> 5 -> 7 -> 2 -> 4 -> 6 -> 8 -> NULL

1.

get 1, and list is 3 -> 5 -> 7 -> 2 -> 4 -> 6 -> 8 -> NULL

  • counter[0]: 1 -> NULL
  • counter[1]: NULL

fill = 1

2.

get 3, and list is 5 -> 7 -> 2 -> 4 -> 6 -> 8 -> NULL

  • counter[0]: NULL
  • counter[1]: 1 -> 3 -> NULL
  • counter[2]: NULL

fill = 2

3.

get 5, and list is 7 -> 2 -> 4 -> 6 -> 8 -> NULL

  • counter[0]: 5 -> NULL
  • counter[1]: 1 -> 3 -> NULL
  • counter[2]: NULL

fill = 1

4.

get 7, and list is 2 -> 4 -> 6 -> 8 -> NULL

  • counter[0]: NULL
  • counter[1]: NULL
  • counter[2]: 1 -> 3 -> 5 -> 7 -> NULL
  • counter[3]: NULL

fill = 3

5.

get 2, and list is 4 -> 6 -> 8 -> NULL

  • counter[0]: 2 -> NULL
  • counter[1]: NULL
  • counter[2]: 1 -> 3 -> 5 -> 7 -> NULL
  • counter[3]: NULL

fill = 3

6.

get 4, and list is 6 -> 8 -> NULL

  • counter[0]: NULL
  • counter[1]: 2 -> 4 -> NULL
  • counter[2]: 1 -> 3 -> 5 -> 7 -> NULL
  • counter[3]: NULL

fill = 3

7.

get 6, and list is 8 -> NULL

  • counter[0]: 6 -> NULL
  • counter[1]: 2 -> 4 -> NULL
  • counter[2]: 1 -> 3 -> 5 -> 7 -> NULL
  • counter[3]: NULL

fill = 3

8.

get 8, and list is NULL.

  • counter[0]: NULL
  • counter[1]: NULL
  • counter[2]: NULL
  • counter[3]: 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> NULL
  • counter[4]: NULL

fill = 4

then return counter[fill - 1].