目录
147.对链表进行插入排序
对链表进行插入排序。
插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。
插入排序算法:
- 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
- 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
- 重复直到所有输入数据插入完为止。
示例 1:
输入: 4->2->1->3 输出: 1->2->3->4示例 2:
输入: -1->5->3->4->0 输出: -1->0->3->4->5
解法:
1.新建一个链表(看成排好序的)
2.遍历原来的链表,取当前节点的值
3.正序遍历排好序的链表,与当前节点的值比较大小,在排序好的链表中找到比当前节点的值大的节点,将当前的结点插入到该节点前,找不到则插在排序好的链表的尾节点
3.循环遍历,直到原来的链表遍历结束
class Solution {
function insertionSortList($head) {
if(is_null($head) || is_null($head->next)) return $head;
//1.新建一个链表,看成是排好序的,该虚拟头节点不与原链表对接
$dummyHead = new ListNode(null);
$curNode = $head;
//2.遍历原来的链表
while ($curNode) {
$nextNode = $curNode->next;
/**
* 3.遍历排好序的链表
* 找到比当前节点的值大的节点,则插入到该节点之前
* 找不到则插在排好序的链表的尾部
*/
$preNode = $dummyHead;
while ($preNode->next && $preNode->next->val < $curNode->val) {
$preNode = $preNode->next; //遍历完成,$preNode指向比当前节点的值大的节点的前一节点,或者尾节点
}
//4.插入操作
$curNode->next = $preNode->next;
$preNode->next = $curNode;
$curNode = $nextNode;
}
return $dummyHead->next;
}
}
148.排序链表
在 O(n log n) 时间复杂度和常数级空间复杂度下,对链表进行排序。
示例 1:
输入: 4->2->1->3 输出: 1->2->3->4示例 2:
输入: -1->5->3->4->0 输出: -1->0->3->4->5
解析:根据题目要求,时间复杂度为O(nlogn),因此该题可以用快排或者归并排序解决,本题采用归并排序。
解法:归并排序的思想
1.利用快慢指针找出中间节点并断开
2.对断开后的两个链表,进行递归继续断开
3.对无法再断开的链表进行排序后再合并
(PS:合并链表的函数实现与LeetCode 21.合并两个有序链表的解题方法一致)
class Solution {
function sortList($head) {
//归并排序
return $this->MergeSort($head);//返回排序好后的头节点
}
function MergeSort($head){
if(is_null($head) || is_null($head->next)) return $head;
//1用快慢指针找出中间节点并断开
$slowNode = $fastNode = $head;
while ($fastNode && $fastNode->next) {
$midNode = $slowNode;//慢指针的前一指针
$slowNode = $slowNode->next;
$fastNode = $fastNode->next->next;
}
$midNode->next = null;
//2.对断开后的两个链表分别排序后再合并
$lHead = $this->MergeSort($head); //head为左半部分头节点
$rHead = $this->MergeSort($slowNode); //slowNode为右半部分头节点
return $this->Merge($lHead,$rHead); //合并过程
}
function Merge($lHead,$rHead){
$dummyHead = new ListNode(null);
$curNode = $dummyHead;
//从小到大依次合并,直到其中一方没有元素
while ($lHead && $rHead) {
if($lHead->val <= $rHead->val){
$curNode->next = $lHead;
$lHead = $lHead->next;
}else{
$curNode->next = $rHead;
$rHead = $rHead->next;
}
$curNode = $curNode->next;
}
//链接剩余的节点
if($lHead)
$curNode->next = $lHead;
else
$curNode->next = $rHead;
return $dummyHead->next;
}
}