[Leetcode Week2]Sort List
Sort List题解
题目来源:https://leetcode.com/problems/sort-list/description/
Description
Sort a linked list in O(n log n) time using constant space complexity.
Solution
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    int partition(vector<int>& arr, int start, int end) {
        int pivot = arr[start];
        int low = start, high = end;
        while (low < high) {
            while (arr[low] <= pivot && low < high)
                ++low;
            while (arr[high] > pivot && low < high)
                --high;
            swap(arr[low], arr[high]);
        }
        if (arr[low] > pivot)
            --low;
        arr[start] = arr[low];
        arr[low] = pivot;
        return low;
    }
    void quickSort(vector<int>& arr, int start, int end) {
        if (start >= end)
            return;
        int pivotIndex = partition(arr, start, end);
        quickSort(arr, start, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, end);
    }
    ListNode* sortList(ListNode* head) {
        if (head == NULL || head -> next == NULL) {
            return head;
        }
        ListNode* temp = head;
        vector<int> arr;
        while (temp != NULL) {
            arr.push_back(temp -> val);
            temp = temp -> next;
        }
        quickSort(arr, 0, arr.size() - 1);
        temp = head;
        int i = 0;
        while (temp != NULL) {
            temp -> val = arr[i++];
            temp = temp -> next;
        }
        return head;
    }
};
解题描述
这道题考察的是链表排序。我首先想到的是把链表里面的元素拷贝到一个vector里面然后再快排,这就跟平时对数组快排的操作一样了,然后写起来也比较好写。但是AC之后觉得,2次拷贝元素的时间会不会有点多?而且还带来了额外的空间开销。于是自己还是写多了一个针对链表的快排:
class Solution {
public:
    void swap(int& a, int& b) {
        int t = a;
        a = b;
        b = t;
    }
    ListNode* partition(ListNode* low, ListNode* high) {
        int key = low -> val;
        ListNode *locNode = low;  // the location node the that key will locate at last
        for (ListNode* tempNode = low -> next; tempNode != high; tempNode = tempNode -> next) {
            if (tempNode -> val < key) {
                locNode = locNode -> next;
                swap(locNode -> val, tempNode -> val);
            }
        }
        swap(low -> val, locNode -> val);
        return locNode;
    }
    void quickSort(ListNode* head, ListNode* tail) {
        ListNode* posNode;
        if (head != tail && head -> next != tail) {  // left close, right open interval
            posNode = partition(head, tail);
            quickSort(head, posNode);
            quickSort(posNode -> next, tail);
        }
        return;
    }
    ListNode* sortList(ListNode* head) {
        quickSort(head, NULL);
        return head;
    }
};
但是实际跑出来结果却是(后提交的是用链表快排):

可能因为vector底层是用数组实现的,访问速度会比链表快一些,所以就算加上了拷贝元素的时间,总体的时间复杂度还是要低于直接对链表进行快排。
更优解法
2018.2.3更新
对链表来说,选择归并排序才是更明智的选择
- 链表无法像数组一样快速随机访问元素,要求排序算法元素访问次数较少且稳定
 - 使用归并排序处理链表不需要像数组一样使用额外的内存,合并链表的时候只需要进行指针连接即可
 
下面给出链表递归归并排序的实现:
class Solution {
private:
    ListNode* merge(ListNode* head1, ListNode* head2) {
        ListNode tempHead(0);
        ListNode *curNode = &tempHead;
        while (head1 && head2) {
            if (head1 -> val <= head2 -> val) {
                curNode -> next = head1;
                head1 = head1 -> next;
            } else {
                curNode -> next = head2;
                head2 = head2 -> next;
            }
            curNode = curNode -> next;
        }
        while (head1) {
            curNode -> next = head1;
            head1 = head1 -> next;
            curNode = curNode -> next;
        }
        while (head2) {
            curNode -> next = head2;
            head2 = head2 -> next;
            curNode = curNode -> next;
        }
        return tempHead.next;
    }
public:
    ListNode* sortList(ListNode* head) {
        if (!head)
            return NULL;
        if (head -> next == NULL)
            return head;
        if (head -> next -> next == NULL) {
            if (head -> val <= head -> next -> val) {
                return head;
            } else {
                ListNode *newHead = head -> next;
                newHead -> next = head;
                head -> next = NULL;
                return newHead;
            }
        }
        ListNode *mid = head, *tail = head;
        while (tail && tail -> next) {
            mid = mid -> next;
            tail = tail -> next -> next;
        }
        ListNode* head2 = sortList(mid -> next);
        mid -> next = NULL;
        head = sortList(head);
        return merge(head, head2);
    }
};
												
											[Leetcode Week2]Sort List的更多相关文章
- [Leetcode Week2]Sort Colors
		
Sort Colors题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/sort-colors/description/ Description Give ...
 - C#版 - LeetCode 148. Sort List 解题报告(归并排序小结)
		
leetcode 148. Sort List 提交网址: https://leetcode.com/problems/sort-list/ Total Accepted: 68702 Total ...
 - 待字闺中之快排单向链表;leetcode之Sort List
		
题目来源.待字闺中.原创@陈利人 .欢迎大家继续关注微信公众账号"待字闺中" 分析:思路和数据的高速排序一样,都须要找到一个pivot元素.或者节点. 然后将数组或者单向链表划分为 ...
 - LeetCode——Insertion Sort List
		
LeetCode--Insertion Sort List Question Sort a linked list using insertion sort. Solution 我的解法,假设第一个节 ...
 - [LeetCode] Wiggle Sort II 摆动排序
		
Given an unsorted array nums, reorder it such that nums[0] < nums[1] > nums[2] < nums[3]... ...
 - [LeetCode] Wiggle Sort 摆动排序
		
Given an unsorted array nums, reorder it in-place such that nums[0] <= nums[1] >= nums[2] < ...
 - [LeetCode] Insertion Sort List 链表插入排序
		
Sort a linked list using insertion sort. 链表的插入排序实现原理很简单,就是一个元素一个元素的从原链表中取出来,然后按顺序插入到新链表中,时间复杂度为O(n2) ...
 - 【Leetcode】Sort List JAVA实现
		
Sort a linked list in O(n log n) time using constant space complexity. 1.分析 该题主要考查了链接上的合并排序算法. 2.正确代 ...
 - [LeetCode] 148. Sort List 解题思路
		
Sort a linked list in O(n log n) time using constant space complexity. 问题:对一个单列表排序,要求时间复杂度为 O(n*logn ...
 
随机推荐
- 【个人笔记】关于C++小数的处理
			
无论是C-Style还是C++-Style的输出,小数都会四舍五入.如果想要截断两种比较好的方法.第一种:利用sscanf输出成字符串,再人为地putchar().第二种:已知钦定保留6位小数,那么可 ...
 - fiddler之弱网测试
			
今天就说一下如何使用fiddler做弱网测试 1.首先要把手机的代理打开,这就不多讲了哈,不懂得话请点传送门:https://www.cnblogs.com/fuxinxin/p/9146693.ht ...
 - 剑指offer-斐波那契数列07
			
题目描述 大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0). n<=39 class Solution: def Fibonacci(self ...
 - 搞ACM的伤不起
			
劳资六年前开始搞ACM啊!!!!!!!!!! 从此踏上了尼玛不归路啊!!!!!!!!!!!! 谁特么跟劳资讲算法是程序设计的核心啊!!!!!! 尼玛除了面试题就没见过用算法的地方啊!!!!!! ...
 - 并查集——poj2524(入门)
			
传送门:Ubiquitous Religions 许多次WA,贴上错的代码随时警示 简单没多加修饰的并查集 [WA1] #include <iostream> #include <c ...
 - vsCode怎么为一个前端项目配置ts的运行环境
			
vsCode为一个前端项目配置ts的运行环境,ts文件保存的时候自动编译成js文件: 假设此前端项目名称为Web:文件结构如图 1. 在根目录中新建一个“.vscode”文件夹,里面建一个“tasks ...
 - iMuseum
			
iMuseum 每日环球展览 iMuseum https://itunes.apple.com/cn/app/%E6%AF%8F%E6%97%A5%E7%8E%AF%E7%90%83%E5%B1%95 ...
 - 【bzoj3997】[TJOI2015]组合数学  Dilworth定理结论题+dp
			
题目描述 给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走.问至少走多少次才能将财宝捡完.此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走 ...
 - BZOJ4592 SHOI2015脑洞治疗仪(线段树)
			
考虑需要资瓷哪些操作:区间赋值为0:统计区间1的个数:将区间前k个0变为1:询问区间最长全0子串.于是线段树维护区间1的个数.0的个数.最长前缀后缀全0子串即可.稍微困难的是用一个log实现将区间前k ...
 - [bzoj4071] [Apio2015]巴邻旁之桥
			
Description 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域 A 和区域 B. 每一块区域沿着河岸都建了恰好 1000000001 栋的建筑,每条岸边的建筑都从 0 编号到 10000 ...