【算法训练】LeetCode#148 排序链表

一、描述

148. 排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表

示例 1:

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2:

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3:

输入:head = []
输出:[]

二、思路

  1. 排序方法有很多,先用冒泡思想,每次找到最大值放到末尾。
  2. 时间复杂度为n方,超时了。
  3. 归并排序,递归调用,不断拆分最后两两排序合并。

三、解题


public static class Solution {
    public static class ListNode {
        int val;
        ListNode next;
        ListNode() {}
        ListNode(int val) { this.val = val; }
        ListNode(int val, ListNode next) { this.val = val; this.next = next; }
    }
    // 冒泡 ,超时了
    public ListNode sortList(ListNode head) {

        if (head == null || head .next == null){
            return head;
        }
        ListNode curNode = head;
        int length = 0; // 得到长度
        while (curNode != null){
            length++;
            curNode = curNode.next;
        }
        boolean flag = false; // 默认false,如果变换过则true,如果结束一轮还是false,表明已经完全升序了
        for (int i = 0 ; i<length; i++){
            ListNode preNode = null;
            curNode = head;
            flag = false;
            for (int j = 0 ; j < length-i-1 ; j++){
                if (curNode.val > curNode.next.val){
                    // 交换位置
                    ListNode tmp = curNode.next.next; // 防止后续链表丢失
                    curNode.next.next = curNode;
                    if (preNode == null){
                        // 如果是头节点位置变换,则需要移动head,否则将丢失头节点
                        head = curNode.next;
                        preNode = curNode.next; // 前驱节点向后移动一位
                    } else {
                        // 如果非头节点变换
                        // 前一节点指向当前节点的后一节点
                        preNode.next = curNode.next;
                    }
                    preNode = curNode.next;
                    curNode.next = tmp;
                    flag = true;
                } else {
                    preNode = curNode; // 前驱节点向后移动一位
                    curNode = curNode.next;
                }
                if (!flag){
                    return head;
                }
            }
        }
        return head;
    }


    // 归并排序
    public ListNode sortListV2(ListNode head) {
        return proccess(head,null);
    }

    // 递归主体,一半一半的拆分
    public ListNode proccess(ListNode head,ListNode tail){
        if (head == null){
            return null;
        }
        if (head.next == tail){
            // 单节点时,直接返回该节点
            head.next = null; // 断链
            return head;
        }
        ListNode slow = head, fast = head;
        while (fast != tail) {
            slow = slow.next;
            fast = fast.next;
            if (fast != tail) {
                fast = fast.next;
            }
        }
        // 找到上半链表的尾巴 slow

        ListNode mid = slow;
        ListNode list1 = proccess(head, mid); // 递归拆分
        ListNode list2 = proccess(mid, tail);
        ListNode sorted = mergeList(list1, list2); // 排序好的合并
        return sorted;

    }

    // 合并两个有序链表
    public ListNode mergeList(ListNode head1,ListNode head2){
        ListNode dummyHead = new ListNode(0);
        ListNode temp = dummyHead, temp1 = head1, temp2 = head2;
        while (temp1 != null && temp2 != null) {
            // 谁小拼接谁
            if (temp1.val <= temp2.val) {
                temp.next = temp1;
                temp1 = temp1.next;
            } else {
                temp.next = temp2;
                temp2 = temp2.next;
            }
            temp = temp.next;
        }
        if (temp1 != null){
            temp.next = temp1;
        } else if (temp2 != null){
            temp.next = temp2;
        }
        return dummyHead.next;
    }


posted @ 2023-01-02 23:10  小拳头呀  阅读(14)  评论(0编辑  收藏  举报