Question


本题难度Medium。有2种算法分别是: 递归法(省时不省空间)和迭代法(省空间不省时间)

1、递归法

【复杂度】
时间 O(N) 空间 O(N) 函数栈深度

【思路】
由于链表只能向后走,因此将较大值往后插入。先对子链表​​​head.next​​进行排序,然后再将head插入到合适的位置,递归进行。

【代码】

public class Solution {
public ListNode insertionSortList(ListNode head) {
//base case
if(head==null)return head;

//require
head.next=insertionSortList(head.next);
ListNode cur=head,tmp=head.next;
while(cur.next!=null&&head.val>cur.next.val){
cur=cur.next;
}
if(cur!=head){
head.next=cur.next;
cur.next=head;
return tmp;
}else
return head;
}
}

2、迭代法

【复杂度】
时间 O(N) 空间 O(1)

【思路】
与方法1相反,将小的节点往前插入。以​​​dummy​​​作为已排序的链表头。每次从待排序链表中取出一个节点,然后在​​dummy​​链表中从头开始进行比较看插到哪里。

[LeetCode]Insertion Sort List_递归

方法2虽然节省空间,但是并省时。真实的插入排序并不是从头开始进行比较,这里是因为链表限制(单向),所以不得已每次从头开始比较。而方法1才是真正符合插入排序精髓的方法(虽然它不省空间)。

【注意】
第4行的代码必须要注释掉,否则就不能将已排序链表和待排序链表区分开。

【代码】

public class Solution {
public ListNode insertionSortList(ListNode head) {
ListNode dummy= new ListNode(Integer.MIN_VALUE);
//dummy.next = head;

for (ListNode cur = head; cur != null;) {
ListNode pos = findInsertPos(dummy, cur.val);
ListNode tmp = cur.next;
cur.next = pos.next;
pos.next = cur;
cur = tmp;
}
return dummy.next;
}

private ListNode findInsertPos(ListNode head, int x) {
ListNode pre = null;
for (ListNode cur = head; cur != null && cur.val <= x; ){
pre = cur; cur = cur.next;
}
return pre;
}
}