Leecode 148. 排序链表

题目描述

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

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

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

看到时间复杂度就想到了快排和归并排序
但是常数级空间复杂度 很明显不能递归调用,那就有点复杂。 先从归并排序的递归开始写起。

  1. 首先需要找到中间节点,然后cut,切断为两个链表,然后递归调用切断函数,直到最后变成两个单个节点的链表,依次排序每一轮递归的链表,再合并。
public static ListNode sortList(ListNode head) {
        if (head == null || head.next == null)
            return head;
        //快慢指针
        ListNode fast = head.next, slow = head;
        //找到中间节点
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        //tmp存储后半部分节点
        ListNode tmp = slow.next;
        //将前半部分节点的末尾置为null
        slow.next = null;

        //递归调用
        ListNode left = sortList(head);
        ListNode right = sortList(tmp);
        //创建前缀链表
        ListNode h = new ListNode(0);
        ListNode res = h;
        //拼接链表
        while (left != null && right != null) {
            if (left.val < right.val) {
                h.next = left;
                left = left.next;
            } else {
                h.next = right;
                right = right.next;
            }
            h = h.next;
        }
        h.next = left != null ? left : right;
        return res.next;
    }

易于理解的版本

public ListNode sortListDemo(ListNode head) {
	return mergeSort(head);
}

private ListNode mergeSort(ListNode head){
	//如果只有一个节点,或者节点为空,直接返回
	if(head == null || head.next == null)
		return head;
	ListNode slow = head;
	ListNode fast = head.next.next;
	ListNode l, r;
	while(fast != null && fast.next != null){
		slow = slow.next;
		fast = fast.next.next;
	}
	//对右半部分进行排序
	r = mergeSort(slow.next);
	
	slow.next = null;
	//对左半部分进行排序
	l = mergeSort(head);
	return(mergeList(l, r));
} 

private ListNode mergeList(ListNode l,ListNode r){
	ListNode tmp = new ListNode(0);
	ListNode res = tmp;
	//不断根据顺序拼接链表
	for(l != null && r != null) {
		if(l.val > r.val){
			res.next = r;
			r = r.next;
		}else{
			res.next = l;
			l = l.next;
		}
		res = res.next;
	}
	//某一个链表不为空,直接拼接在后方
	res.next = (l == null)? r : l;
	return tmp.next;
}

最后一个不使用递归的办法

//不使用递归
    public ListNode sortListDemo2(ListNode head) {
        if(head == null || head.next == null) return head;
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        int len = getListLen(head);
        int itrv = 1;
        while(itrv < len) {
            ListNode pre = dummy;
            ListNode h = dummy.next;
            // 找到合并链表的h1和h2头节点
            while(h!=null) {
                int i = itrv;
                ListNode h1 = h;
                for(; h != null && i > 0; i--) {
                    h = h.next;
                }
                // i>0说明没有链表2直接返回
                if(i > 0) break;
                ListNode h2 = h;
                i = itrv;
                for(; h != null && i > 0; i--) {
                    h = h.next;
                }
                // 求出两个链表的长度
                int c1 = itrv;
                int c2 = itrv - i;

                //合并
                while(c1 > 0 && c2 > 0) {
                    if(h1.val < h2.val) {
                        pre.next = h1;
                        h1 = h1.next;
                        c1--;
                    }else {
                        pre.next = h2;
                        h2 = h2.next;
                        c2--;
                    }
                    pre = pre.next;
                }
                pre.next = c1 > 0 ? h1 : h2;
                while(c1 > 0 || c2 > 0) {
                    pre = pre.next;
                    c1--;
                    c2--;
                }
                pre.next = h;
            }
            itrv*=2;
        }
        return dummy.next;

link
这不是我自己写的 感觉自己还没想通,所以贴了别人实现的代码。 还得好好看一下 继续努力吧

你可能感兴趣的:(java,数据结构与算法)