题目
给定单个链表的头 head
,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。
插入排序 算法的步骤:
- 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
- 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
- 重复直到所有输入数据插入完为止。
下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。
对链表进行插入排序。
示例 1:
输入: head = [4,2,1,3]
输出: [1,2,3,4]
示例 2:
输入: head = [-1,5,3,4,0]
输出: [-1,0,3,4,5]
提示:
- 列表中的节点数在
[1, 5000]
范围内 -5000 <= Node.val <= 5000
题解
解题思路
大致的步骤是从前往后逐个把元素按照大小插入到前面已排好序节点中的适当位置,但是有一些细节需要注意。
-
最开始是可以把第一个结点当做是已排好序结点,从第二个结点开始插入排序;
-
为了可以统一处理在每个位置的插入,新建一个 dummyHead 结点用于指向 Head,这样同时也方便最后返回结果;
-
在遍历查找要插入的位置时,要实现插入,需要使用一个指针 prev 指向插入位置的前一个结点;
-
除了要使用 cur 指向当前正在处理的结点,还需要使用 lastSorted 指针指向当前已排序部分的最后一个结点,一方面是为了能把当前结点在当前位置移除掉,然后也可以方便拿到下一个要处理的结点 lastSorted.next,另一方面,在处理每个结点时,可以先判断 cur.val 值是否大于等于 lastSorted.val,如果是,直接把 lastSorted 移到 cur 即可,无需执行多一次插入位置查找,提高效率。
代码
/**
* 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 insertionSortList(ListNode head) {
ListNode cur = head.next;
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode lastSorted = head;
while (cur != null) {
if (lastSorted.val <= cur.val) {
lastSorted = cur;
} else {
ListNode prev = dummyHead;
while(cur.val >= prev.next.val) {
prev = prev.next;
}
lastSorted.next = cur.next;
cur.next = prev.next;
prev.next = cur;
}
cur = lastSorted.next;
}
return dummyHead.next;
}
}
复杂度分析
- 时间复杂度:O(n²)
其中 n 是链表的长度。 - 空间复杂度:O(1)
优质项目推荐
推荐一个可用于练手、毕业设计参考、增加简历亮点的项目。
lemon-puls/txing-oj-backend: Txing 在线编程学习平台,集在线做题、编程竞赛、即时通讯、文章创作、视频教程、技术论坛为一体
公众号
有兴趣可以关注公众号一起学习更多的干货哈!