【PHP解法==LeetCode链表类型(链表排序)】147.对链表进行插入排序 && 148.排序链表

目录

147.对链表进行插入排序

148.排序链表


147.对链表进行插入排序

对链表进行插入排序。


插入排序的动画演示如上。从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示)。
每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中。

插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。

示例 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;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值