【32】重排链表 | 对链表进行插入排序(LeetCode 143 | 147)

重排链表

问题描述

给定一个单链表 L:L0→L1→…→Ln-1→Ln ,
将其重新排列后变为: L0→Ln→L1→Ln-1→L2→Ln-2→…

你不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

例子:
【32】重排链表 | 对链表进行插入排序(LeetCode 143 | 147)

解题思路

第一个想到的就是分离再合并的方法:
①将链表分成前部分和后部分;
②将后部分反转顺序;
③合并前后部分。

示意图:
【32】重排链表 | 对链表进行插入排序(LeetCode 143 | 147)
代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    int length(ListNode* head){//求链表的长度
        int n=0;
        while(head){
            n++;
            head = head->next;
        }
        return n;
    }

    void hebing(ListNode* l1,ListNode* l2){ //合并链表
        while(l1 && l2){
            ListNode* q = l1->next;
            ListNode* p = l2->next;
            l1->next = l2;
            l1 = q;
            if(!l1) break;
            l2->next = q;
            l2 = p;
        }
    }

    void reorderList(ListNode* head) {
        if(!head || !head->next) return ;
        int mid = length(head)/2;
        ListNode* cur = head;
        ListNode* hou;
        int i=0;
        while(cur){//分离链表
            i++;
            if(i<mid){
                cur = cur->next;
            }else if(i == mid || i == mid+1){
                ListNode* temp = cur->next;
                hou = cur;
                cur->next = nullptr;
                cur = temp;
            }else{ //将后半段反序
                ListNode* q = cur->next;
                cur->next = hou;
                hou = cur;
                cur = q;
            }
        }
        hebing(head,hou);
    }
};

时间复杂度:O(n)
空间复杂度:O(1)

对链表进行插入排序

问题描述

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

插入排序算法:

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

解题思路

按照插入排序的算法步骤来写即可:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode() : val(0), next(nullptr) {}
 *     ListNode(int x) : val(x), next(nullptr) {}
 *     ListNode(int x, ListNode *next) : val(x), next(next) {}
 * };
 */
class Solution {
public:
    ListNode* insertionSortList(ListNode* head) {
        if (!head || !head->next)//若链表为空或只有一个结点不需要排序
            return head;
        ListNode* pre_head = new ListNode(0,head);
        ListNode* last = head;
        ListNode* curr = head->next;
        while (curr) {
            if (last->val <= curr->val) {//若当前结点的值大于排好序的最后一个值,则直接插在其后
                last = last->next;
            } else {//否则,从头遍历,找到合适的位置插入
                ListNode *prev = pre_head;
                while (prev->next->val <= curr->val)
                    prev = prev->next;
                last->next = curr->next;
                curr->next = prev->next;
                prev->next = curr;
            }
            curr = last->next;
        }
        return pre_head->next;
    }
};

心得

好像开始会写链表的题了,就是解题慢了些。

上一篇:LeetCode 147. 对链表进行插入排序


下一篇:范德蒙方法解三次方程之 U+V 代数运算笔记