题目:力扣
题目要求nlgn的时间复杂度完成排序。
那么时间复杂度为nlgn的排序算法大概有三种:
1.快排
2.堆排
3.归并
快排不怎么合适,需要不停地交换结点,而且还需要维护双指针,可能不太合适
堆排更不太合适了,也依赖于数组
归并虽然也依赖于数组,但是依赖性没那么大,是一种分治的思想
自顶向下:
public class Solution1 {
public ListNode sortList(ListNode head) {
if (head == null) {
return null;
}
// 只有一个结点了 那就直接返回了
if (head.next == null) {
return head;
}
List<ListNode> split = split(head);
ListNode left = sortList(split.get(0));
ListNode right = sortList(split.get(1));
return mergeTwoLists(left, right);
}
public List<ListNode> split(ListNode head) {
ListNode slow = head, fast = head.next;
while (fast != null) {
fast = fast.next;
if (fast != null) {
fast = fast.next;
slow = slow.next;
}
}
List<ListNode> res = new ArrayList<>();
ListNode second = slow.next;
slow.next = null;
res.add(head);
res.add(second);
return res;
}
// 合并链表用的
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// 需要四个指针
// 1 头结点指针 head
// 2 顺序结点的尾结点指针 tail
// 3 l1未排序的结点指针 l1UnhandledHead
// 4 l2未排序的结点指针 l2UnhandledHead
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
// 初始化
ListNode head = l1.val <= l2.val ? l1 : l2;
ListNode tail = head;
ListNode l1UnhandledHead = head == l1 ? l1.next : l1;
ListNode l2UnhandledHead = head == l2 ? l2.next : l2;
while (l1UnhandledHead != null || l2UnhandledHead != null) {
if (l1UnhandledHead == null) {
tail.next = l2UnhandledHead;
break;
} else if (l2UnhandledHead == null) {
tail.next = l1UnhandledHead;
break;
} else {
if (l1UnhandledHead.val <= l2UnhandledHead.val) {
tail.next = l1UnhandledHead;
l1UnhandledHead = l1UnhandledHead.next;
} else {
tail.next = l2UnhandledHead;
l2UnhandledHead = l2UnhandledHead.next;
}
tail = tail.next;
}
}
return head;
}
public static void main(String[] args) {
ListNode first = new ListNode(1);
ListNode second = new ListNode(2);
ListNode third = new ListNode(3);
first.next = second;
second.next = third;
Solution1 solution1 = new Solution1();
List<ListNode> split = solution1.split(first);
System.out.println(split.get(0).val + " " + split.get(1).val);
}
}
其实题目要求的是空间复杂度为常数。
自顶向下因为是递归的原因肯定满足不了,所以完全可以自底向上。
自底向上代码如下,写起来是有点麻烦:
public class Solution {
public ListNode sortList(ListNode head) {
if (head == null) {
return null;
}
if (head.next == null) {
return head;
}
int listLen = 0;
ListNode tempNode = head;
while (tempNode != null) {
listLen++;
tempNode = tempNode.next;
}
ListNode res = head;
boolean setHeadFLag = false;
// 这里我需要两个指针
// orderPre 排序区域结点的前一个结点指针
// orderNext 排序区域结点的后一个结点指针
ListNode orderPre = null, orderNext = null;
// 还需要另外两个指针
// curr 正在处理的结点指针
ListNode curr;
for (int i = 1; i < listLen; i <<= 1) {
// 自底向上的归并排序
curr = res;
setHeadFLag = false;
orderPre = null;
ListNode tempP = res;
for (int l = 1; l < 2 * i && tempP != null; l++) {
tempP = tempP.next;
}
orderNext = tempP == null ? null : tempP.next;
while (curr != null) {
// 代表还有的处理
ListNode firstList = curr;
for (int l = 1; l < i && curr != null; l++) {
curr = curr.next;
}
ListNode temp = curr == null ? null : curr.next;
if (curr != null) {
curr.next = null;
}
ListNode secondList = temp;
curr = temp;
for (int l = 1; l < i && curr != null; l++) {
curr = curr.next;
}
temp = curr == null ? null : curr.next;
if (curr != null) {
curr.next = null;
}
ListNode mergedListHead = mergeTwoLists(firstList, secondList);
if (!setHeadFLag) {
res = mergedListHead;
setHeadFLag = true;
}
if (orderPre != null) {
orderPre.next = mergedListHead;
}
while (mergedListHead.next != null) {
mergedListHead = mergedListHead.next;
}
mergedListHead.next = orderNext;
orderPre = mergedListHead;
curr = temp;
for (int l = 1; l < 2 * i && temp != null; l++) {
temp = temp.next;
}
orderNext = temp == null ? null : temp.next;
}
}
return res;
}
// 合并链表用的
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
// 需要四个指针
// 1 头结点指针 head
// 2 顺序结点的尾结点指针 tail
// 3 l1未排序的结点指针 l1UnhandledHead
// 4 l2未排序的结点指针 l2UnhandledHead
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
// 初始化
ListNode head = l1.val <= l2.val ? l1 : l2;
ListNode tail = head;
ListNode l1UnhandledHead = head == l1 ? l1.next : l1;
ListNode l2UnhandledHead = head == l2 ? l2.next : l2;
while (l1UnhandledHead != null || l2UnhandledHead != null) {
if (l1UnhandledHead == null) {
tail.next = l2UnhandledHead;
break;
} else if (l2UnhandledHead == null) {
tail.next = l1UnhandledHead;
break;
} else {
if (l1UnhandledHead.val <= l2UnhandledHead.val) {
tail.next = l1UnhandledHead;
l1UnhandledHead = l1UnhandledHead.next;
} else {
tail.next = l2UnhandledHead;
l2UnhandledHead = l2UnhandledHead.next;
}
tail = tail.next;
}
}
return head;
}
}