[TOC]

​ 本文主要记录链表的循环、分割、排序的相关LeetCode题目的实现代码,直接给出本文各个题目的答案,供有需求的读者学习或复制。

一、循环链表的LeetCode题目

61. 旋转链表(中等难度)

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        // 空链表直接返回空
        if(head==nullptr) return nullptr;
        // 找到最后一个节点并统计len
        ListNode* p=head;
        int len=1;
        while(p->next){
            p=p->next;
            len++;
        }
        // 如果k==len,直接返回
        if(k==len){
            return head;
        } 
        // 如果k!=len,修改循环链表
        else{
            p->next=head;
        }
        // 找到第len-k个节点
        p=head;
        if(k>len) k=k%len;
        int i=len-k-1;
        while(i--){
            p=p->next;
        }
        ListNode* res=p->next;//新的头结点
        p->next=nullptr;//解除循环
        return res;
    }
};

剑指 Offer II 029. 排序的循环链表(中等难度)

​ 思路:如果链表为空,直接新建结点,改变指针指向后返回即可;如果链表不空:先找到循环链表的尾巴,即最大值结点,找到了尾巴相当于也找到了最小值结点,因为tail->next就是最小的;判断插入值是否比最小值小或者比最大值大,如果满足,就插入到tail后面即可;如果插入值介于最小和最大之间,循环查找插入位置,当某个结点值比插入值小且那个结点的后一个结点比插入结点大时,即可插入。

class Solution {
public:
    Node* insert(Node* head, int insertVal) {
        Node* newNode = new Node(insertVal);
        // 如果链表为空,直接新建节点,改变指针指向后返回
        if(head==NULL){
            newNode->next=newNode;
            return newNode;
        }
        // 找到循环链表中的最大值,设为循环链表的尾部
        Node* p=head->next;
        Node* tail=head;
        int max=head->val;
        while(p!=head){
            if(p->val>=max) {
                max=p->val;
                tail=p;
            }
            p=p->next;
        }
        // 如果插入值大于最小值或者小于最小值,插入tail之后即可
        if(insertVal>max||insertVal<tail->next->val){
            Node* temp =tail->next;//保存tail->next
            tail->next=newNode;
            newNode->next=temp;
        }
        else{
            // 如果插入值介于最小值和最大值之间,则遍历寻找插入位置
            while(p){
                if(p->val<=insertVal&&p->next->val>=insertVal){
                    Node* temp =p->next;//保存p->next
                    p->next=newNode;//p指向新节点
                    newNode->next=temp;//新节点指向p->next
                    break;
                }
                p=p->next;
            }
        }
        return head;
    }
};

二、链表分隔的LeetCode题目

86. 分隔链表(中等难度)

面试题 02.04. 分割链表(中等难度)

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        ListNode* small=new ListNode(0);
        ListNode* pSmall=small;
        ListNode* large=new ListNode(0);
        ListNode* pLarge=large;
        // 找出所有值比listNode小的
        ListNode* p=head;
        while(p){
            if(p->val<x) {
                pSmall->next=p;//添加一个新节点
                pSmall=pSmall->next;//指针前进一步
            }else{
                pLarge->next=p;
                pLarge=pLarge->next;
            }
            p=p->next;
        }
        pLarge->next=nullptr;//去除掉最后
        pSmall->next=large->next;//拼接
        return small->next;
    }
};

328. 奇偶链表(中等难度)

class Solution {
public:
    ListNode* oddEvenList(ListNode* head) {
        ListNode* front=new ListNode(0);//结果链表的前部分,奇数
        ListNode* curFront=front;
        ListNode* back=new ListNode(0);//结果链表的后部分,偶数
        ListNode* curBack=back;
        // 遍历整个链表
        ListNode* p=head;
        bool flag=true;
        while(p){
            if(flag){
                curFront->next=p;
                curFront=curFront->next;
                flag=false;
            }else{
                curBack->next=p;
                curBack=curBack->next;
                flag=true;
            }
            p=p->next;
        }
        // 将后链表的末尾去除
        curBack->next=nullptr;
        // 将前链表的末尾接上后链表
        curFront->next=back->next;
        return front->next;
    }
};

三、链表排序的LeetCode题目

1、链表中点+反转链表+合并链表

143. 重排链表(中等难度)

剑指 Offer II 026. 重排链表(中等难度)

class Solution {
public:
    // 获取中间节点
    ListNode* getMiddleNode(ListNode* head){
        ListNode* slow=head;
        ListNode* fast=head;
        while(fast->next&&fast->next->next){
            slow=slow->next;
            fast=fast->next->next;
        }
        return slow;
    }
    // 反转整个链表
    ListNode* reverseList(ListNode* head){
        ListNode* left=nullptr;
        ListNode* right=head;
        while(right){
            // 保存
            ListNode* temp=right->next;
            // 反转
            right->next=left;
            // 前进
            left=right;
            right=temp;
        }
        return left;
    }

     // 在l1链表中插入l2链表1,2  4,3  -》1,4,2  3
    void mergeList(ListNode* l1,ListNode* l2){
        ListNode* res=new ListNode(0);//结果链表的虚拟头结点
        ListNode* p=res;
        while(l1&&l2){
            p->next=l1;
            l1=l1->next;
            p->next->next=l2;
            l2=l2->next;
            p=p->next->next;
        }
        // l1和l2可能是不等长的,有一个会多出一个元素
        if(l1) p->next=l1;
        if(l2) p->next=l2;
        l1=res->next;
        // ListNode* p1;
        // ListNode* p2;
        // while(l1&&l2){
        //     // 保存
        //     p1 = l1->next;//2
        //     p2 = l2->next;//3
        //     // 连接
        //     l1->next = l2;//1指向4
        //     l2->next = p1;//4指向2
        //     // 移动指针
        //     l1 = p1;//l1指向2
        //     l2 = p2;//l2指向3
        // }
    }
    void reorderList(ListNode* head) {
        if(head==nullptr) return;
        // 寻找链表中点
        ListNode* mid = getMiddleNode(head);
        // 将链表分割为左右两部分
        ListNode* l1 = head;
        ListNode* l2 = mid->next;
        mid->next = nullptr;//将l1和l2分割开
        // 反转右半部分的链表
        l2 = reverseList(l2);
        // 将链表合并起来
        mergeList(l1, l2);
    }
};

2、调整相邻节点的顺序

24. 两两交换链表中的节点(中等难度)

方法一:

class Solution {
public:
    // 方法:分隔链表+合并链表:
    ListNode* swapPairs(ListNode* head) {
        // 分隔链表:遍历一遍将奇数节点和偶数节点分开存放
        ListNode* oddHead=new ListNode(0);//奇数元素所在链表
        ListNode* pOdd=oddHead;
        ListNode* evenHead=new ListNode(0);//偶数元素所在链表
        ListNode* pEven=evenHead;
        bool isOdd=true;
        while(head){
            if(isOdd){
                pOdd->next=head;
                pOdd=pOdd->next;
                isOdd=false;
            }else{
                pEven->next=head;
                pEven=pEven->next;
                isOdd=true;
            }
            head=head->next;
        }
        pOdd->next=nullptr;
        pEven->next=nullptr;
        // 合并链表
        ListNode* myHead=new ListNode(0);
        ListNode* p=myHead;
        pOdd=oddHead->next;
        pEven=evenHead->next;
        while(pEven&&pOdd){
            p->next=pEven;
            pEven=pEven->next;
            p->next->next=pOdd;
            pOdd=pOdd->next;
            p=p->next->next;
        }
        if(pOdd) p->next=pOdd;
        if(pEven) p->next=pEven;
        return myHead->next;
    }
};

方法二:指针法

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        // 新建虚拟头结点
        ListNode* myHead=new ListNode(0);
        myHead->next=head;
        // 遍历指针
        ListNode* cur=myHead;
        while(cur->next&&cur->next->next){
            // 新建指针
            ListNode* slow=cur->next;
            ListNode* fast=cur->next->next;
            // 改变指向
            cur->next=fast;//cur指向fast
            slow->next=fast->next;//slow指向fast的后一位
            fast->next=slow;//fast指向slow
            // cur前进一步
            cur=slow;
        }
        return myHead->next;
    }
};

3、插入排序

147. 对链表进行插入排序(中等难度)

class Solution {
public:
    // 从小到大排序,难点:插入算法的思想,搜索插入位置
    ListNode* insertionSortList(ListNode* head) {
        if(head==nullptr) return nullptr;
        // 新建虚拟头结点
        ListNode* myHead=new ListNode(0);
        myHead->next=head;
        // 双指针进行插入排序
        ListNode* lastSorted=head;//最后一个排序好的节点
        ListNode* cur=head->next;// 当前遍历到的节点
        while(cur){
            // 如果当前节点值>最后一个排序好的节点,直接+1
            if(cur->val>=lastSorted->val){
                lastSorted=lastSorted->next;
            }
            // 如果当前节点值<最后一个排序好的节点,从头遍历寻找插入位置
            else{
                ListNode* prev = myHead;//从虚拟头结点开始
                // 遍历找到第一个prev->next的值大于cur的值
                while (prev->next->val <= cur->val) {
                    prev = prev->next;
                }
                // 保存cur的后一个元素
                lastSorted->next = cur->next;//排序好的节点+1
                // 在prev后面插入cur
                cur->next = prev->next;//当前节点
                prev->next = cur;
            }
            cur = lastSorted->next;
        }
        return myHead->next;
    }
};

4、归并排序

148. 排序链表(中等难度)

剑指 Offer II 077. 链表排序(中等难度)

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        return sortList(head, nullptr);//归并排序
    }
    // 分割2个单链表
    ListNode* sortList(ListNode* head,ListNode* tail) {
        // 如果头结点为空,直接返回
        if(head==nullptr) return nullptr;
        // 如果头结点的下一个节点就是尾结点,说明当前链表只有1个元素
        if (head->next == tail) {
            head->next = nullptr;
            return head;
        }
        // 快慢指针找到head到tail的中间元素
        ListNode* slow = head, *fast = head;
        while (fast != tail) {
            slow = slow->next;
            fast = fast->next;
            if (fast != tail) {
                fast = fast->next;
            }
        }
        ListNode* mid = slow;//中间元素
        ListNode* l1 = sortList(head, mid); // 将左半部分变为有序链表
        ListNode* l2 = sortList(mid, tail); // 将右半部分变为有序链表
        return mergeList(l1, l2);
    }
    // 合并2个单链表
    ListNode* mergeList(ListNode* l1,ListNode* l2){
        ListNode* myHead= new ListNode(0);
        ListNode* p1=l1,*p2=l2,*res=myHead;

        while(p1&&p2){
            if(p1->val<=p2->val){
                res->next=p1;
                p1=p1->next;
            }
            else{
                res->next=p2;
                p2=p2->next;
            }
            res=res->next;
        }
        while(p1){
            res->next=p1;
            p1=p1->next;
            res=res->next;
        }
        while(p2){
            res->next=p2;
            p2=p2->next;
            res=res->next;
        }
        return myHead->next;
    }
};