首页 > 其他分享 >链表高频题

链表高频题

时间:2024-09-28 23:34:16浏览次数:5  
标签:pre ListNode cur nullptr next 链表 高频

链表高频题

160. 相交链表

#include <vector>
#include <iostream>
#include <algorithm>

struct ListNode {
    int val;
    ListNode *next;

    ListNode(int x) : val(x), next(NULL) {}
};

class Solution {
public:
    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        if (headA == nullptr || headB == nullptr) return nullptr;
        ListNode *a = headA;
        ListNode *b = headB;
        int diff = 0;
        while (a->next != nullptr) {
            a = a->next;
            diff++;
        }
        while (b->next != nullptr) {
            b = b->next;
            diff--;
        }
        // 根本就不重合
        if (a != b) return nullptr;
        // 较长的链表赋给 a
        if (diff > 0) {
            a = headA;
            b = headB;
        } else {
            a = headB;
            b = headA;
        }
        diff = abs(diff);
        // 较长的链表先走 diff 步
        while (diff-- != 0)
            a = a->next;
        // 距离尾节点距离相同时,同时出发
        while (a != b) {
            a = a->next;
            b = b->next;
        }
        return a;
    }
};

25. K 个一组翻转链表

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

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 *reverseList(ListNode *head, ListNode *tail) {
        ListNode *pre = tail->next, *cur = head, *next;
        ListNode *nextNode = tail->next;
        while (cur != nullptr && cur != nextNode) {
            next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }

    ListNode *reverseKGroup(ListNode *head, int k) {
        // 虚拟头节点,接在链表最前面,使得第一段要反转的链表部分的处理和后面统一
        ListNode *dummyHead = new ListNode(0, head);
        ListNode *pre = dummyHead;
        ListNode *left = dummyHead;
        ListNode *right;
        // 后移次数
        int count;

        while (pre->next != nullptr) {
            // left、right 移到下一段要反转的链表的头部
            left = pre->next;
            right = left;
            // right 后移 k-1 个节点
            for (count = k - 1; count != 0 && right->next != nullptr; count--)
                right = right->next;
            // 链表元素总数小于 k
            if (count != 0) return dummyHead->next;
            // 把反转后的部分接到前面的链表上
            pre->next = reverseList(left, right);
            // 反转后 left 节点变成反转部分的尾节点,也就是下一段要反转的部分的上一个节点
            pre = left;
        }

        return dummyHead->next;
    }
};

138. 随机链表的复制

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

class Node {
public:
    int val;
    Node *next;
    Node *random;

    Node(int _val) {
        val = _val;
        next = nullptr;
        random = nullptr;
    }
};

class Solution {
public:
    Node *copyRandomList(Node *head) {
        if (head == nullptr) return nullptr;
        Node *pre = head;

        // 遍历原链表,在每个节点后面插入新节点
        while (pre != nullptr) {
            // 复制原节点的值
            Node *node = new Node(pre->val);
            // 接在原节点的后面
            node->next = pre->next;
            pre->next = node;
            pre = pre->next->next;
        }

        pre = head;
        // 遍历链表,复制 random 指针
        while (pre != nullptr) {
            if (pre->random != nullptr)
                pre->next->random = pre->random->next;
            pre = pre->next->next;
        }

        pre = head;
        Node *res = head->next;
        Node *cur = head->next;
        // 分离出复制出的链表
        while (cur != nullptr && cur->next != nullptr) {
            // 改回原链表节点的 next 指针
            pre->next = pre->next->next;
            pre = pre->next;
            // 新链表的节点从原链表中分离出来,串在一起
            cur->next = cur->next->next;
            cur = cur->next;
        }
        // 原链表尾节点的 next 指针
        pre->next = nullptr;
        return res;
    }
};

234. 回文链表

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

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:

    // 返回向上取整的中间节点
    // [1, 2, 3, 4] 返回 3
    ListNode *findMid(ListNode *head) {
        ListNode *slow = head;
        ListNode *fast = head;
        while (fast != nullptr && fast->next != nullptr) {
            fast = fast->next->next;
            slow = slow->next;
        }
        return slow;
    }

    // 原地反转
    ListNode *reverseList(ListNode *head) {
        ListNode *pre = nullptr;
        ListNode *cur = head;
        ListNode *next;
        while (cur != nullptr) {
            next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }

    bool isPalindrome(ListNode *head) {
        ListNode *mid = findMid(head);
        mid = reverseList(mid);

        ListNode *p = head;
        ListNode *q = mid;
        while (q != nullptr) {
            if (p->val != q->val) return false;
            p = p->next;
            q = q->next;
        }
        return true;
    }
};

142. 环形链表 II

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

struct ListNode {
    int val;
    ListNode *next;

    ListNode(int x) : val(x), next(nullptr) {}
};

class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 环外节点数 a,环内节点数 b
        // 快慢指针经过的节点个数关系: f = 2s
        // 相遇时: f = s + n*b -> s = n*b, f = 2*n*b
        // 走到入口节点经过的节点个数 k = a + n*b, 先前进 a 步到入口节点, 然后在环里转圈
        // f = 0, s = n*b -> f = a, s = a + n*b 相遇在入口节点

        ListNode *slow = head, *fast = head;
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
            // 首次相遇时,slow 已经跑了 b 步,只需跑 a 步就能到达入口
            // fast 返回开头 head 节点,也只需跑 a 步就能到达入口
            // 此时 a 是几并不知道,但是可以确定的是,slow 和fast 都在跑 a 步就会在入口相遇
            if (slow == fast) {
                fast = head;
                // 此时 f = 0, s = 1*b
                while (slow != fast) {
                    slow = slow->next;
                    fast = fast->next;
                }
                // 结束时 f = a, s = a + 1*b
                return slow;
            }
        }

        return nullptr;
    }
};

148. 排序链表

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

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 *merge(ListNode *l1, ListNode *l2) {
        if (l1 == nullptr || l2 == nullptr) return l1 == nullptr ? l2 : l1;
        ListNode *dummyHead = new ListNode();
        ListNode *pre = dummyHead;
        while (l1 != nullptr && l2 != nullptr) {
            if (l1->val < l2->val) {
                pre->next = l1;
                l1 = l1->next;
            } else {
                pre->next = l2;
                l2 = l2->next;
            }
            pre = pre->next;
        }
        if (l1 != nullptr) pre->next = l1;
        if (l2 != nullptr) pre->next = l2;
        return dummyHead->next;
    }

    // 时间复杂度 O(n * logn),额外空间复杂度 O(1),稳定
    ListNode *sortList(ListNode *head) {
        // 统计链表长
        int len = 0;
        ListNode *temp = head;
        while (temp != nullptr) {
            len++;
            temp = temp->next;
        }

        ListNode *dummyHead = new ListNode();
        dummyHead->next = head;

        // 步长每次乘二
        for (int gap = 1; gap < len; gap <<= 1) {
            ListNode *pre = dummyHead;
            ListNode *cur = dummyHead->next;

            // 每次从一组元素的首个元素节点开始(两个子链表为一组)
            while (cur != nullptr) {
                // 长度为 gap 的子链表 l1
                ListNode *l1 = cur;
                int i = 1;
                while (i < gap && cur->next != nullptr) {
                    cur = cur->next;
                    i++;
                }

                // 子链表 l2
                ListNode *l2 = cur->next;
                // 把 l2 从 l1 后面断开
                cur->next = nullptr;

                // 找到子链表 l2 的末尾,l2 可能是最后一个子链表并且长度小于等于 gap
                // l2 后面可能还有
                cur = l2;
                i = 1;
                while (i < gap && cur != nullptr && cur->next != nullptr) {
                    cur = cur->next;
                    i++;
                }

                ListNode *next = nullptr;
                // l2 后面还有节点时
                if (cur != nullptr) {
                    // 下一组的起点(两个子链表为一组)
                    next = cur->next;
                    // 断开,l2变成完成的一条链表
                    cur->next = nullptr;
                }

                // 把这组的两个子链表合并
                pre->next = merge(l1, l2);
                // pre 移到合并后的最后一个节点,等待接上下一组合并后的首个节点
                while (pre->next != nullptr)
                    pre = pre->next;
                // 进入下一组的归并
                cur = next;
            }
        }

        return dummyHead->next;
    }
};

标签:pre,ListNode,cur,nullptr,next,链表,高频
From: https://www.cnblogs.com/sprinining/p/18438640

相关文章

  • 代码随想录算法训练营Day03-链表 | LC203移除链表元素、LC707设计链表、LC206反转链表
    目录前言LeetCode203.移除链表元素思路完整代码LeetCode707.设计链表思路完整代码LeetCode206.反转链表思路完整代码今日总结前言拖延症犯了,哈哈,拖了一天LeetCode203.移除链表元素给你一个链表的头节点head和一个整数val,请你删除链表中所有满足Node.val......
  • 代码随想录算法训练营第三天|203.移除链表元素,707.设计链表,206.反转链表
    203.移除链表元素文章链接:https://programmercarl.com/0203.移除链表元素.html#算法公开课视频讲解:https://www.bilibili.com/video/BV18B4y1s7R9题目出处:https://leetcode.cn/problems/remove-linked-list-elements/卡哥在这里讲解了为什么要使用虚拟头节点,以及使用和不使......
  • 面试题 02.07. 链表相交
    明天回家喽,最近在学习的瓶颈期,感觉学的东西好难,有厌学的心理,但是我相信过了这段煎熬的时期,就好了。classSolution{public:ListNode*getIntersectionNode(ListNode*headA,ListNode*headB){intna=0,nb=0;ListNode*tempA=headA;L......
  • 量化金融数据:股票、期货、期权、外汇、外盘期货、美股、港股、数字货币分钟、tick高频
    银河数据:yinhedata.comA股:沪深京行情数据及接口,包含Level2、十档、五档、tick、分钟、日、财务数据、宏观数据等。美股:美股行情历史数据分钟、日、周、月、财务报表、宏观数据,含复权和不复权数据等。国内期货:国内所有期货交易所的行情数据,Level2、0.5s高频数据、分钟、日、......
  • 链表分割 1.2版本
    现有一链表的头指针ListNode* pHead,给一定值x,编写一段代码将所有小于x的结点排在其余结点之前,且不能改变原来的数据顺序,返回重新排列后的链表的头指针。思路:大致可以分为两个区域来存储数据:区域一存储小于36的节点,区域二存储大于36的节点.可以将这两个区域视为两个链表......
  • 算法训练营第三天| 203.移除链表元素、707.设计链表、206.反转链表
    203.移除链表元素状态:完成个人思路:首先令head符合条件,之后判断这个head是否为空,空的话返回空节点;非空的话继续进行。令pre=head;cur=head->next,只要cur非空,就判断cur的值的情况,如果需要删除,就改变pre->next和cur;如果不需要删除就继续检查下一个。看完讲解视频之后的想法:我......
  • 代码随想录算法训练营第三天 | 熟悉链表
    链表的存储方式数组是在内存中是连续分布的,但是链表在内存中可不是连续分布的。链表是通过指针域的指针链接在内存中各个节点。所以链表中的节点在内存中不是连续分布的,而是散乱分布在内存中的某地址上,分配机制取决于操作系统的内存管理。链表的定义template<typenameT>......
  • 力扣 简单 206.反转链表
    文章目录题目介绍题解题目介绍题解法一:双指针在遍历链表时,将当前节点的next改为指向前一个节点。由于节点没有引用其前一个节点,因此必须事先存储其前一个节点。在更改引用之前,还需要存储后一个节点。最后返回新的头引用。代码如下:classSolution{public......
  • 力扣 中等 92.反转链表 II
    文章目录题目介绍题解题目介绍题解classSolution{publicListNodereverseBetween(ListNodehead,intleft,intright){//创建一个哑节点,它的next指向头节点,方便处理ListNodedummy=newListNode(0,head);//p0用于......
  • 算法题:用队列实现一个链表
    下面是添加了注释的ListNode类和LinkedListQueue类,以帮助理解每个部分的功能和目的://定义链表节点类,用于存储队列中的元素classListNode{intval;//存储节点的值ListNodenext;//指向下一个节点的指针//构造函数,用于创建新的节点ListNod......