链表面试题OJ

1. 头插或三指针翻转法

1.1 LeetCode206题—反转链表

链接: https://leetcode-cn.com/problems/reverse-linked-list/在这里插入图片描述
①首选方法:头插法

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        ListNode* newHead = nullptr;
        ListNode* cur = head;
        while(cur != nullptr)
        {
            ListNode* next = cur->next;
            cur->next = newHead;
            newHead = cur;
            cur = next;
        }
        return newHead;
    }
};

②三指针翻转法

class Solution {
public:
    //翻转链表还有一个经典的解法就是三指针翻转
    ListNode* reverseList(ListNode* head) {
        if(head == nullptr || head->next == nullptr)
            return head;
        ListNode* n1 = nullptr,*n2 = head,*n3= head->next;
        while(n2 != nullptr)
        {
            n2->next = n1;
            n1 = n2;
            n2 = n3;
            //因为n3是最先出去的,如果解引用就会出现崩的情况
            if(n3 != nullptr)
            {
                n3 = n3->next;
            }
        }
        return n1;
    }
};

1.2 LeetCode25题—K个一组翻转链表

链接:https://leetcode-cn.com/problems/reverse-nodes-in-k-group/
在这里插入图片描述
这题要设置一个带哨兵位的头节点,目的就是为了能够返回链表的头。

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        //设置一个带哨兵位的头节点,目的是为了最终能够轻松的返回链表的头
        ListNode* Head = new ListNode(0);
        Head->next = head;//头节点初始化工作完毕

        ListNode* prev = Head;
        ListNode* cur = head;
        while(cur)
        {
            //首先应该验证是否此时满足k个
            //并且对于这K个节点的链表,我们需要知道他的尾部,位的就是能够链接下一组K个节点
            ListNode* tmpTail = cur;
            int count = 1;
            while(tmpTail->next && count++ < k)
            {
                tmpTail = tmpTail->next;
            }
            //不知道到底是这上面两个条件的哪一个跳出来的循环,需要做一个判断
            if(count < k)
            {
                //说明此时是不足K个了,那么就不需要进行翻转了,但是这个一个迭代的过程,有可能这是一个子过程
                prev->next = cur;
                return Head->next;
            }
            //说明此时是满足k个了,那么我们对着k个进行一下反转
            //但是需要保存下一组的头节点,然后把这个组从链表中断开,然后再对这个K个一组的链表进行反转
            ListNode* tmpCur = tmpTail->next;
            tmpTail->next = nullptr;
            prev->next = Reverse(cur);
            //接下来就是迭代的过程,需要进入下一组K个的链表中
            prev = cur;
            cur = tmpCur;
        }
        return Head->next;
    }

    ListNode* Reverse(ListNode* head)
    {
        ListNode* prev = nullptr;
        ListNode* cur = head;
        while(cur)
        {
            ListNode* next = cur->next;
            cur->next = prev;
            prev = cur;
            cur = next;
        }
        return prev;
    }
};

1.3 LeetCode23题—合并K个升序链表

LeetCode题目链接:https://leetcode-cn.com/problems/merge-k-sorted-lists/
在这里插入图片描述
其实就是合并两个链表然后不停的自己和自己合并的一个过程

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        //自己要和自己合并呢
        ListNode* rethead = nullptr;
        for(auto& e: lists)
        {
            rethead = mergeTwoLists(rethead,e);
        }
        return rethead;
    }
private:
    ListNode* mergeTwoLists(ListNode* l1,ListNode* l2)
    {
        //首先就是应该写出合并两个链表的代码
        if(l1 == nullptr && l2 == nullptr)
            return nullptr;
        if(l1 == nullptr && l2 != nullptr)
            return l2;
        if(l1 != nullptr && l2 == nullptr)
            return l1;
        //走到这里说明两个都不是空,那么就考虑开始合并的问题
        ListNode* head = nullptr,*tail = nullptr;
        if(l1->val <= l2->val)
        {
            head = tail = l1;
            l1 = l1->next;
        }
        else
        {
            head = tail = l2;
            l2 = l2->next;
        }
        while(l1 && l2)
        {
            if(l1->val <= l2->val)
            {
                tail->next = l1;
                l1 = l1->next;
            }
            else
            {
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
        }
        if(l1)
        {
            tail->next = l1;
        }
        else
        {
            tail->next = l2;
        }
        return head;
    }
};

2. LeetCode203题—移除链表元素

链接: https://leetcode-cn.com/problems/remove-linked-list-elements/
在这里插入图片描述

class Solution {
public:
    ListNode* removeElements(ListNode* head, int val) {
        ListNode* prev = nullptr,*cur = head;
        while(cur)
        {
            if(cur->val == val)
            {
                //此时还要考虑不会不是一开始就是相同的
                if(cur == head)
                {
                    head = cur->next;
                    delete cur;
                    cur = head;
                }
                else
                {
                    prev->next = cur->next;
                    delete cur;
                    cur = prev->next;
                }
            }
            else 
            {
                prev = cur;
                cur = cur->next;
            }
        }
        return head;
    }
};

3. 快慢指针法及其变形

3.1 LeetCode876题—链表的中间结点

链接: https://leetcode-cn.com/problems/middle-of-the-linked-list/
在这里插入图片描述

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        //这道题提示给定了链表的节点数介于1——100之间,所以链表不可能为nullptr
        ListNode* slow = head,*fast = head;
        //1 2 3 4  如果是偶数个判断的条件就是fast != nullptr
        //1 2 3 4 5 如果是奇数个判断条件就是fast->next != nullptr
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        return slow;
    }
};

3.2 剑指offer22题—链表中倒数第k个结点

链接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/
在这里插入图片描述
题解:先让快指针走k步,然后快慢指针在一起走,当快指针都到空的时候,慢指针刚好在倒数第k个结点的位置

class Solution {
public:
    //这道题我没有考虑到K的值是大于链表的长度的,为什么还过了
    ListNode* getKthFromEnd(ListNode* head, int k) {
        ListNode* slow = head,*fast = head;
        //这也就是我上面所考虑到的问题,如果K的值大于了你链表的长度呢?
        while(fast && k!=0)
        {
            //这里是有可能空指针访问的,越界应该要报错的,但是LeetCode这里处理不好
            fast = fast->next;
            k--;
        }

        while(fast)
        {
            slow = slow->next;
            fast = fast->next;
        }
        return slow;

    }
};

3.3 剑指offer27题—链表的回文结构

链接:https://leetcode-cn.com/problems/aMhZSa/
在这里插入图片描述

题解:使用到了快慢指针用来找到中间结点,然后使用翻转链表,在比较两个链表的结点是否都相同

class Solution {
public:
    //首先找到中间节点,然后在对后半部分进行逆置,在对比前半部分和后半部分是否相同
    bool isPalindrome(ListNode* head) {
        ListNode* slow = head,*fast = head;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        //现在我们就假设设个链表是一个偶数
        //那么根据实例一,就可以知道此事slow所指向的位置就是下中位数的3,然后我们以这个结点进行翻转
        ListNode* newNode = nullptr;
        ListNode* cur = slow;
        while(cur)
        {
            ListNode* next = cur->next;
            cur->next = newNode;
            newNode = cur;
            cur = next;
        }
        //走到这里newNode就是翻转过后新链表的头结点
        while(newNode)
        {
            if(newNode->val != head->val)
                return false;
            head = head->next;
            newNode = newNode->next;
        }
        return true;
    }
};

3.4 LeetCode141题—环形链表I

链接:https://leetcode-cn.com/problems/linked-list-cycle/
在这里插入图片描述

题解:为什么快指针走的是慢指针的两倍,走三倍或者4倍不行吗?
答案是不行,因为只有快指针是慢指针的两倍时候,假设他们都进入环里以后开始相差的距离是x,那么他们分别每走一步,距离就缩短为x-1,x-2…0,一定会相遇,如果是3倍或者4倍那么在有些情况下就有可能会错过

class Solution {
public:
    bool hasCycle(ListNode *head) {
        ListNode* slow = head,*fast = head;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;

            if(slow == fast)
                return true;
        }
        return false;
    }
};

3.5 LeetCode142题—环形链表II

链接:https://leetcode-cn.com/problems/linked-list-cycle-ii/
在这里插入图片描述
题解:这个是需要经过验证的,2(L+X) = L + NC+X,得到L=NC-X,刚好从他们在环里相遇的点开始走和头结点开始走到第一个相遇的点的距离都是L

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        ListNode* slow = head,*fast = head;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;

            if(slow == fast)
                break;
        }

        //要排除掉没有相遇的情况,确保一定是break出来的
        if(fast == nullptr || fast->next == nullptr)
            return nullptr;
        ListNode* meet = fast;
        while(head!=fast)
        {
            head = head->next;
            fast = fast->next;
        }
        return fast;
    }
};

4. 找到长链表然后走差值步,然后同时走

4.1 LeetCode160题—相交链表

链接:https://leetcode-cn.com/problems/intersection-of-two-linked-lists/
在这里插入图片描述
题解:让长链表先走他们的差距步,这样就保证了两个链表的长度是一样的了,然后他们在同时走,那么相遇的结点就是相交结点

class Solution {
public:
    //这道题找的是相交的结点,不是值
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        int la = 0,lb = 0;
        //一般不要轻易改变head,使用一个变量来替换head
        ListNode* curA = headA;
        while(curA)
        {
            la++;
            curA = curA->next;
        }
        ListNode* curB = headB;
        while(curB)
        {
            lb++;
            curB = curB->next;
        }
        ListNode* longList = headA,*shortList = headB;
        if(la < lb)
        {
            longList = headB;
            shortList = headA;
        }
        int gap = abs(la-lb);
        while(gap)
        {
            longList = longList->next;
            gap--;
        }
        //此时走到这里就说明了他们两个此时是一样长的
        while(longList)
        {
            if(longList!= shortList)
            {
                longList = longList->next;
                shortList = shortList->next;
            }
            else
            {
                return longList;
            }
        }
        return nullptr;
    }
};

5. 创造带哨兵位的头结点和尾结点法

5.1 牛客网—链表分割

链接: link.
在这里插入图片描述

class Partition {
public:
    ListNode* partition(ListNode* pHead, int x) {
        // write code here
        //带哨兵位的头结点是不保存任何的有效数值的,并且对这个头结点里面存储的数据进行初始化
        ListNode* lesserHead,*lesserTail;
        ListNode* greaterHead,*greaterTail;
        lesserHead = new ListNode(1);
        greaterHead= new ListNode(1);
        lesserTail = lesserHead;
        greaterTail = greaterHead;
        lesserHead->next = greaterHead->next = nullptr; //对头结点进行初始化
        ListNode* cur = pHead;
        while(cur)
        {
            if(cur->val < x)
            {
                lesserTail->next = cur;
                lesserTail = lesserTail->next;
            }
            else
            {
                greaterTail->next = cur;
                greaterTail = greaterTail->next;
            }
            cur = cur->next;
        }
        //因为有可能造成回环
        //例如题目如果是 1 9 3 5 6 7   x=4那么没有问题
        //如果是1 9 3 5 6 7 2 x=4 那么就出现链表回环问题了
        greaterTail->next = nullptr;
        lesserTail->next = greaterHead->next;
        //这一步是为了要释放到所开辟的两个头结点,所以要保存一下
        ListNode* list = lesserHead->next;
        delete lesserHead;
        delete greaterHead;
        return list;
     }
};

6. LeetCode21题—合并两个有序链表

链接:https://leetcode-cn.com/problems/merge-two-sorted-lists/
在这里插入图片描述

class Solution {
public:
    ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
        if(l1 == nullptr && l2 == nullptr)
            return nullptr;
        if(l1 == nullptr)
            return l2;
        if(l2 == nullptr)
            return l1;
        //走到这里就说明l1和l2都不为空
        //定义一个头结点和尾结点
        struct ListNode* head = nullptr,*tail = nullptr;
        if(l1->val <= l2->val)
        {
            head = tail = l1;
            l1 = l1->next;
        }
        else
        {
            head = tail = l2;
            l2 = l2->next;
        }

        //此时就是取较小的结点值进行尾插就可以
        while(l1 && l2)
        {
            if(l1->val <= l2->val)
            {
                tail->next = l1;
                l1 = l1->next;
            }
            else
            {
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
        }
        if(l1)
        {
            tail->next = l1;
        }
        else
        {
            tail->next = l2;
        }

        return head;
    }
};

7. LeetCode148题—排序链表

LeetCode链接:https://leetcode-cn.com/problems/sort-list/
在这里插入图片描述
解题思路:
①使用快慢指针法,找到中间节点,将链表递归不断的拆分
②使用合并两个有序链表子函数,不断的合并

class Solution {
public:
    ListNode* sortList(ListNode* head) {
        //我们应该将节点拆分到只剩下一个或者为空,停止拆分
        if(head == nullptr || head->next == nullptr)
            return head;
        //在这里我们要使用快慢指针法,找到中间节点,然后不停的去递归拆分
        ListNode* slow = head,*fast = head->next;
        while(fast && fast->next)
        {
            slow = slow->next;
            fast = fast->next->next;
        }
        ListNode* nextHead = slow->next;
        slow->next = nullptr;
        return merge(sortList(head),sortList(nextHead));
    }
    ListNode* merge(ListNode* l1,ListNode* l2)
    {
        ListNode* dummy = new ListNode(0),*tail = dummy;
        while(l1 && l2)
        {
            if(l1->val <= l2->val)
            {
                tail->next = l1;
                l1 = l1->next;
            }
            else
            {
                tail->next = l2;
                l2 = l2->next;
            }
            tail = tail->next;
        }
        if(l1)
            tail->next = l1;
        if(l2)
            tail->next = l2;
        return dummy->next;
    }
};

8. LeetCode138题—复制带随机指针的链表

LeetCode链接:https://leetcode-cn.com/problems/copy-list-with-random-pointer/
在这里插入图片描述

第一种方法:拷贝出的结点链接在原结点后面,然后在修改拷贝结点里面next和random,最后还原原链表的样子

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if(head == nullptr)
            return nullptr;
        Node* cur = head;
        while(cur)
        {   
            //创建一个拷贝结点
            Node* copy = new Node(cur->val);
            copy->next = nullptr;
            copy->random = nullptr;

            Node* next = cur->next;
            //然后修改链接的关系
            cur->next = copy;
            copy->next = next;
            cur = next;
        }
        //此时就给每个结点都复制了一个相同的结点,但是里面的random关系却还没有改变
        cur = head;
        while(cur)
        {
            Node* copy = cur->next;
            if(cur->random)
            {
                copy->random = cur->random->next;
            }
            else
            {
                copy->random = nullptr;
            }
            cur = copy->next; 
        }
        //上面就把所有的random关系都修改完了,剩下的就是恢复原来的链表结构了
        cur = head;
        Node* newHead = cur->next;
        while(cur)
        {
            Node* copy = cur->next;
            Node* next = copy->next;

            cur->next = next;
            if(next)
            {
                copy->next = next->next;
            }
            else
            {
                copy->next = nullptr;
            }
            cur = next;
        }
        return newHead;
    }
};

**推荐方法(应为比第一题写的要少很多)**第二种方法:Hash映射—构成原结点和结点之间的映射关系,第一次变量就是为了侯建映射,第二次遍历则是为了修改拷贝出来链表中结点的next和random

class Solution {
public:
    //第二种方法就是使用Hash,但是要想清楚,到底是什么和什么只要要构成映射,才能够解出来这道题
    //从题解上来看是,构建原结点和新节点之间的映射关系
    Node* copyRandomList(Node* head) {
        if(head == nullptr)
            return nullptr;
        unordered_map<Node*,Node*> HashMap;
        Node* cur = head;
        while(cur)
        {
            HashMap[cur] = new Node(cur->val);
            cur = cur->next;
        }
        cur = head;
        Node* copyHead = HashMap[cur];
        while(cur)
        {
            HashMap[cur]->next = HashMap[cur->next];
            HashMap[cur]->random = HashMap[cur->random];
            cur = cur->next;
        }
        return copyHead;
    }
};

9. LeetCode147题—对链表进行插入排序

链接:https://leetcode-cn.com/problems/insertion-sort-list/
在这里插入图片描述

题解:就是插入排序的思想,把第一个当做有顺序的,然后拿着剩下的结点去插入,当问题解不下去的时候,就把最简单的想写了,然后剩下的就自然出来了,比如说先把头插的方法写掉,剩下的就是中间插入或者尾插了

class Solution {
public:
    ListNode* insertionSortList(ListNode* head) {
        if(head == nullptr || head->next == nullptr)
            return head;
        //这两步就相当于取了第一个结点作为排序的头
        ListNode* sortHead = head;

        //剩下的就是拿从第二个结点到结束的结点进行插入
        ListNode* cur = head->next;
        sortHead->next = nullptr;
        while(cur)
        {
            ListNode* next = cur->next;
            //拿着结点去插入,但是这里又三种可能1.cur->val值小于等sortHead,头插
            //2.cur->val值大于sortHead->val,那就往后走,此时有可能是尾插也有可能是中间插入
            if(cur->val <= sortHead->val)
            {
                //头插
                cur->next = sortHead;
                sortHead = cur;
            }
            else
            {
                //中间插入或者尾插,前面已经排除了头插的可能
                ListNode* sortprev = sortHead,*sortcur = sortprev->next;
                while(sortcur)
                {
                    if(cur->val>sortcur->val)
                    {
                        sortprev = sortcur;
                        sortcur = sortcur->next;
                    }
                    else
                    {
                        sortprev->next = cur;
                        cur->next = sortcur;
                        break;
                    }
                }
                if(sortcur == nullptr)
                {
                    sortprev->next = cur;
                    cur->next = nullptr;
                }
            }
            cur = next;
        }
        return sortHead;
    }
};

10. 删除链表中重复的元素

10.1 LeetCode83题—删除链表中重复的结点I

链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list/
在这里插入图片描述

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head == nullptr || head->next==nullptr)
            return head;
        ListNode* cur = head;
        while(cur->next)
        {
            if(cur->val == cur->next->val)
            {
                cur->next = cur->next->next;
            }
            else
            {
                cur = cur->next;
            }
        }
        return head;
    }
};

10.2 LeetCode82题—删除链表中重复的结点II

链接:https://leetcode-cn.com/problems/remove-duplicates-from-sorted-list-ii/
在这里插入图片描述
题解:先把正常的写掉,然后在考虑不正常的情况,比如头部就有相同的,尾部有相同的两种情况在进行考虑

class Solution {
public:
    ListNode* deleteDuplicates(ListNode* head) {
        if(head == nullptr || head->next == nullptr)
            return head;
        ListNode* prev = nullptr,*cur = head,*next = cur->next;
        while(next)
        {
            //如果实在想不出来应该怎么写的时候,应该就想把正常的写完,在考虑不正常的情况
            if(cur->val != next->val)
            {
                prev = cur;
                cur = next;
                next = next->next;
            }
            else
            {
                //头就开始相等
                while(next &&cur->val == next->val)
                {
                    next = next->next;
                }

                if(prev)
                {
                    prev->next = next;
                }
                else
                {
                    head = next;
                }
                //尾部开始相等
                //跳出上面的循环有两种可能,一种就是cur->val != next->val 包含了头不正常和中间不正常
                //还有一种情况就是尾不正常 也就是跳出循环的第二个可能
                
                //为了避免内存泄漏,要把结点释放掉
                while(cur!= next)
                {
                    ListNode* Node = cur;
                    cur = cur->next;
                    delete Node;
                }
                //因为尾部相同的时候,是由可能cur指向了next的空,然后在解引用就会崩了
                if(next)
                    next = cur->next;
            }
        }
        return head;
    }
};

11. LeetCode19题—删除链表的倒数第N个节点

在这里插入图片描述
解题思路:其实这道题是由一个小技巧的,当我们在使用快慢指针的时候,那个slow所在的位置就是我们要找的倒数第N个节点,但问题是我们此时是需要删除这个节点,然后让他的前一个连接他的后一个节点的。

 //你不得不感慨人家的思想到底是有多么的nb
 //我们最终的目的是什么,其实就想找到我们要删除那个节点的上一个节点,这样我们就可以改变链接关系了
class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* newHead = new ListNode(0);
        newHead->next = head;
        ListNode* slow = newHead,*fast = newHead;
        while(n--)
        {
            fast = fast->next;
        }
        //此时的slow和fast相距N步,然后我们让他们同时走
        while(fast->next)
        {
            slow = slow->next;
            fast = fast->next;
        }
        //即使是最极端的情况代码依旧满足
       slow->next = slow->next->next;
       ListNode* retNode = newHead->next;
       delete newHead;//一定要避免内存泄漏的问题
       return retNode;
    }
};

12. LeetCode24题—两两交换链表中的节点

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* newHead = new ListNode(-1);
        newHead->next = head;
        ListNode* tmp = newHead;
        while(tmp->next && tmp->next->next)
        {
            ListNode* node1 = tmp->next;
            ListNode* node2 = tmp->next->next;
            //此时开始修改链接关系
            tmp->next = node2;
            ListNode* next = node2->next;
            node2->next = node1;
            node1->next = next;
            tmp = node1;
        }
        return newHead->next;
    }
};

解法2:这道题其实还可以使用栈的方法,下来还需要再做一遍

13. LeetCode2题—两数相加

在这里插入图片描述

class Solution {
public:
    ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
       //给较短的链表补0,达到两个链表一样长的目的
       ListNode* newHead = new ListNode(-1);
       newHead->next = nullptr;
       ListNode* cur = newHead;
       int carry = 0;
       while(l1 || l2)
       {
           int x = l1 == nullptr ? 0:l1->val;
           int y = l2 == nullptr ? 0:l2->val;
           int sum = x + y + carry;

           cur->next = new ListNode(sum % 10);
           carry = sum / 10;
           cur = cur->next;
           if(l1)
            l1 = l1->next;
           if(l2)
            l2 = l2->next;
       }
       //如果此时跳出来的时候还有进位此时也应该考虑到
        if(carry != 0)
           cur->next = new ListNode(carry);
        return newHead->next;
    }
};

14. LeetCode61题—旋转链表

在这里插入图片描述
解题思路:先找到链表中的为节点,然后再找到下标为n-k那个节点,然后修改链接关系就可以了

class Solution {
public:
    ListNode* rotateRight(ListNode* head, int k) {
        if(head == nullptr || head->next == nullptr)
            return head;
        int length = 1;
        ListNode* tail = head;
        while(tail->next)
        {
            length++;
            tail = tail->next;
        }
        //此时tail所待的位置就是我们要知道的tail节点
        k %= length; //因为这种旋转很有可能就是会超过链表本身的长度

        //此时需要找到n-k下标的节点
        ListNode* cur = head;
        int n = length-k-1;
        while(n--)
        {
            cur = cur->next;
        }
        //此时cur就是我们要找的前半段的尾节点(找到n-k为下标的节点)
        tail->next = head;
        ListNode* newHead = cur->next;
        cur->next = nullptr;
        return newHead;
    }
};

15. LeetCode92题—反转链表

在这里插入图片描述

class Solution {
public:
    ListNode* ReverseList(ListNode* phead)
    {
        if(phead == nullptr || phead->next == nullptr)
            return phead;
        ListNode* prev = nullptr;
        ListNode* cur = phead;
        while(cur)
        {
            ListNode* next = cur->next;
            cur->next = prev;
            prev = cur;
            cur = next;
        }
        return prev;
    }
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        //找到left下标的节点,在找到right下标的节点,然后都断开,然后翻转,在链接起来
        if(head == nullptr || head->next == nullptr)
            return head;
        ListNode* newHead = new ListNode(-1);
        newHead->next = head;
        ListNode* prev = newHead;
        //找到left的前一个节点
        for(int i = 0;i<left-1;++i)
        {
            prev = prev->next;
        }
        //prev指向的left的前一个节点
        ListNode* leftnode = prev->next;
        ListNode* rightnode = leftnode;
        prev->next = nullptr;
        for(int i = 0;i<right-left;++i)
        {
            rightnode = rightnode->next;
        }
        //此时rightnode就是我们右节点待的位置
        ListNode* tail = rightnode->next;
        rightnode->next = nullptr;
        //此时就是修改链接关系
        prev->next = ReverseList(leftnode);
        leftnode->next = tail;
        return newHead->next;
    }
};

16. LeetCode86题—分割链表

在这里插入图片描述
解题思路:这道题是再牛客上面做过的,就是定义一个专门比x小的链表,和一个专门比x大的链表,最后再改变链接关系即可

class Solution {
public:
    ListNode* partition(ListNode* head, int x) {
        //简单点说就是只要比他小的就链接在
        ListNode* lesserhead = new ListNode(0);
        ListNode* greaterhead = new ListNode(0);
        ListNode* lessertail = lesserhead; 
        ListNode* greatertail = greaterhead; 
        ListNode* cur = head;
        while(cur)
        {
            if(cur->val < x)
            {
                lessertail->next = cur;
                lessertail = lessertail->next;
            }
            else
            {
                greatertail->next = cur;
                greatertail = greatertail->next;
            }
            cur = cur->next;
        }
        lessertail->next = greaterhead->next;
        greatertail->next = nullptr;
        ListNode* rethead = lesserhead->next;
        delete greaterhead;
        delete lesserhead;
        return rethead;
    }
};

16. LeetCode1721题—交换链表中的节点

在这里插入图片描述
这道题可千万不敢趣交换两个节点,其实交换两个节点的值就完全ok了,不要把过程整复杂化了

class Solution {
public:
    //为什么老想着要去交换节点呢? 
    //我们应该是交换两个节点里面的值呀
    ListNode* swapNodes(ListNode* head, int k) {
        ListNode* newHead = new ListNode(-1);
        newHead->next = head;
        ListNode* slow =newHead,*fast = newHead;
        while(k--)
        {
            fast = fast->next;
        }
        ListNode* firstk = fast;
        while(fast)
        {
            slow = slow->next;
            fast = fast->next;
        }
        ListNode* lastk = slow;
        int tmp = firstk->val;
        firstk->val = lastk->val;
        lastk->val = tmp;
        return newHead->next; 
    }
};

17. LeetCode328题—奇偶链表

在这里插入图片描述
解题思路:我觉得这道题本身是不难的,但是为什么我还是会被卡住,需要好好的思考一下,这个问题?

class Solution {
public:
    //奇数索引组合在一起,偶数索引组合在一起
    //其实何以使用数组把他们全部放在里面,然后在修改链接关系,但是这样空间复杂度就是O(N),所以是不行的
    ListNode* oddEvenList(ListNode* head) {
        if(head == nullptr || head->next == nullptr)
            return head;
        //其实这里通俗一点是这样子的,我们知道了奇链表的头,在定义一个奇的尾,我们不停的移动这个尾部
        //当然了,定义了一个偶数的头
        ListNode* EvenHead = head->next;
        ListNode* odd = head;
        ListNode* even = EvenHead;
        //就看整体来说,就可以了
        while(odd->next && even->next)
        {
            //这里肯定是要迭代起来的
            odd->next = even->next;
            odd = odd->next;
            even->next = odd->next;
            even = even->next;
        }
        //修改链接关系
        odd->next = EvenHead;
        return head; 
    }
};

18. LeetCode237题—删除链表中的节点

在这里插入图片描述
解题思路:其实对于这道题如果我们知道他的前一个节点,那么修改将会非常的容易,但是问题就出现在不知道前一个节点,我们只知道当前节点,所以最好的方式就是,将后一个节点的值赋给要删除的节点,然后我们删除当前节点的下一个相同值的节点,就会简单很多。

class Solution {
public:
    //但是这道题中我们发现我们并不知道头节点
    //你他妈的这个思路接了,既然我们不知道要删除的上一个节点的值,
    //那么我们直接就给他把下一个节点赋值给我们要删除的节点,然后我们在这两个相同的值的节点中选择一个删除就好了
    void deleteNode(ListNode* node) {
        ListNode* next = node->next;
        node->val = next->val;
        //此时就像示例1中,我们知道了此时链表是[4,1,1,9];然后我们删除一个我们最容易的
        //最终我们返回的依旧是[4,1,9]复合题意
        node->next = next->next;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值