【java算法题 28-3】48. 排序链表

83 阅读1分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第 天,点击查看活动详情


题目三、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 = []

输出:[]

/ 提示:

  • 链表中节点的数目在范围 [0, 5 * 104] 内
  • -105 <= Node.val <= 105

解题思路

我们需要给链表节点值进行排序。

我是用的排序方法是归并排序,我们知道,归并排序首先需要获得排序元素的中间元素位置。

但是链表又没有办法向数组那样通过下标获取,所以我们需要使用到快慢指针,快指针一次走两个节点,慢指针一次走一个节点,那么快指针遍历到链表结尾时,我们的慢指针所在位置就是中间节点的位置。

这时候我们借助递归,用同样的方式将每一个子链表通过中间节点平分,最后得到单个的节点,然后相邻的两个节点按照升序合并,这就是归并操作。

我们不断对相邻的两个节点进行归并操作,将归并好的节点按照顺序放入准备好的新链表中,最后返回新链表的头节点即可!

最主要还是理解归并排序的步骤、模板。

提交代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
       return sort(head,null);               //调用递归方法
    }
    //递归方法
    public ListNode sort(ListNode head,ListNode tail){
        if(head == null){      //头节点为空,返回空值
            return head;
        }
        if(head.next == tail){ //节点最终平分至单节点
            head.next = null;  //结点指向空值
            return head;       //返回节点
        }
        ListNode fast = head,slow = head;  //设置快慢指针
        while(fast != tail){               //快指针遍历到结尾前
            slow = slow.next;              //满指针后移
            fast = fast.next;              //快指针后移
            if(fast != tail){              //依旧未到尾部
            fast = fast.next;              //快指针第二次后移
            }
        }
        ListNode mid = slow;               //中间节点就是满指针当前节点
        ListNode list1 = sort(head,mid);   //同样方式平分左子链表
        ListNode list2 = sort(mid,tail);   //同样方式平分右子链表
        ListNode sorted = merge(list1,list2);  //调用归并操作方法
        return sorted;                         //返回升序链表头节点
    }
    public static ListNode merge(ListNode list1,ListNode list2){
        //创建新的链表,存放升序节点
        ListNode list = new ListNode();
        ListNode temp1 = list1;    //两个相邻的链表
        ListNode temp2 = list2;
    ListNode temp = list;
    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;
    }
    if(temp2 != null){
        temp.next = temp2;
    }
    return list.next;           //返回升序链表
    }
}

提交结果

在这里插入图片描述