leetcode148.排序链表

心已入冬 提交于 2019-12-28 05:45:58

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

示例 1:

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

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

思路:
1.归并排序,一般都是使用递归版本,递归版本不能保证常数级的时间复杂度

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        //归并排序
        if(head == null||head.next == null)//head.next == null别忘记了
            return head;
        ListNode fast = head.next;
        ListNode slow = head;
        int len = 0;
        while(fast != null&&fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
            len++;
        }
        fast = slow.next;
        slow.next = null;//把前后两段给切开
        ListNode k1 = sortList(head);
        ListNode k2 = sortList(fast);
        return mergeList(k1,k2);
    }
    public ListNode mergeList(ListNode k1,ListNode k2){
        if(k1 == null && k2 == null){
            return null;
        }
        ListNode res = new ListNode(0);//我新建了一个链表头res,这里的合并链表的空间复杂度其实是O(1)
        //,因为它后面连接的节点都是已经存在了的,都是直接指过去的
        ListNode pre = res;
        ListNode p1 = k1;
        ListNode p2 = k2;
        while(p1 != null && p2 != null){
            if(p1.val <= p2.val){
                res.next = p1;
                p1 = p1.next;        
            }else{
                res.next = p2;
                p2 = p2.next;
            }
            res = res.next;
        }
        res.next = p1==null? p2,p1;
        return pre.next;
    }
}

2.归并排序的非递归版本
bottom-to-up 的归并思路是这样的:先两个两个的 merge,完成一趟后,再 4 个4个的 merge,直到结束。举个简单的例子:[4,3,1,7,8,9,2,11,5,6].

step=1: (3->4)->(1->7)->(8->9)->(2->11)->(5->6)
step=2: (1->3->4->7)->(2->8->9->11)->(5->6)
step=4: (1->2->3->4->7->8->9->11)->5->6
step=8: (1->2->3->4->5->6->7->8->9->11)

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
       ListNode tmp = head;
        int len = 0;
        while(tmp != null){
            tmp = tmp.next;
            //fast = fast.next.next;
            len++;
        }
        ListNode left = head;
        ListNode right = null;
        ListNode cur = head;
        ListNode tail = new ListNode(0);
        ListNode res = tail;
        for(int step = 1;step < len;step = step*2){
        	cur = head;
            while(cur != null){
                left = cur;
                tmp = cut(cur,step);
                if(tmp == null){
                    right = null;
                    cur = null;
                }else{
                    right = tmp.next;
                    tmp.next = null;//将左半部分砍断
                    tmp = cut(right,step);
                    if(tmp == null)
                        cur = null;
                    else{
                        cur = tmp.next;
                        tmp.next = null;
                    }
                    
                }
                res.next = mergeList(left,right);
                while(res.next != null){
                    res = res.next;
                }
            }
            head = tail.next;
            res = tail;
        }
        return head;
    }    
    public ListNode cut(ListNode cur,int step){
        while(step != 1){
            if(cur == null)
                return null;
            cur = cur.next;
            step--;
        }
        return cur;
    }
    public ListNode mergeList(ListNode k1,ListNode k2){
        if(k1 == null && k2 == null){
            return null;
        }
        ListNode res = new ListNode(0);
        ListNode pre = res;
        ListNode p1 = k1;
        ListNode p2 = k2;
        while(p1 != null && p2 != null){
            if(p1.val <= p2.val){
                res.next = p1;
                p1 = p1.next;        
            }else{
                res.next = p2;
                p2 = p2.next;
            }
            res = res.next;
        }
        res.next = p1 == null? p2:p1;
        return pre.next;
    }
}

3.快速排序
借鉴别人的代码

class Solution {
public ListNode sortList(ListNode head) {
        if(head==null||head.next==null) return head;
        // 没有条件,创造条件。自己添加头节点,最后返回时去掉即可。
        ListNode newHead=new ListNode(-1);
        newHead.next=head;
        return quickSort(newHead,null);
    }
    // 带头结点的链表快速排序
    private ListNode quickSort(ListNode head,ListNode end){
        if (head==end||head.next==end||head.next.next==end) return head;
        // 将小于划分点的值存储在临时链表中
        ListNode tmpHead=new ListNode(-1);
        // partition为划分点,p为链表指针,tp为临时链表指针
        ListNode partition=head.next,p=partition,tp=tmpHead;
        // 将小于划分点的结点放到临时链表中
        while (p.next!=end){
            if (p.next.val<partition.val){
                tp.next=p.next;
                tp=tp.next;
                p.next=p.next.next;
            }else {
                p=p.next;
            }
        }
        // 合并临时链表和原链表,将原链表接到临时链表后面即可
        tp.next=head.next;
        // 将临时链表插回原链表,注意是插回!(不做这一步在对右半部分处理时就断链了)
        head.next=tmpHead.next;
        quickSort(head,partition);
        quickSort(partition,end);
        // 题目要求不带头节点,返回结果时去除
        return head.next;
    }
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!