leetcode hot100 链表(二)

news2025/7/23 22:55:09

书接上回:

leetcode hot100 链表(一)-CSDN博客

8.删除链表的倒数第N个结点

class Solution {
public:
    ListNode* removeNthFromEnd(ListNode* head, int n) {
        ListNode* curr=head;
        int len=0;
        while(curr){
            curr=curr->next;
            len++;
        }
        int pos=len-n;
        if(pos==0){
            ListNode* newHead=head->next;
            return newHead;
        }
        curr=head;
        while(--pos) curr=curr->next;  //目标是把curr移动到要删除结点的前面
        curr->next=curr->next->next;
        return head;
    }
};

9.两两交换链表中的结点

        参考leetcode灵神题解:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        ListNode* dummy=new ListNode(0,head); //dummy->val=0&&dummy->next=head;
        ListNode* node0=dummy;
        ListNode* node1=head;
        while(node1&&node1->next){
            ListNode* node2=node1->next;
            ListNode* node3=node2->next;
            node0->next=node2;
            node2->next=node1;
            node1->next=node3;
            node0=node1;
            node1=node3;
        }
        return dummy->next;
    }
};

10.k个一组反转链表

        和上题使用了相同的命名体系。

class Solution {
public:
    ListNode* reverseKGroup(ListNode* head, int k) {
        ListNode* dummy=new ListNode(0,head);
        ListNode* node0=dummy;
        ListNode* node1=node0->next;
        while(node1&&node1->next){
            ListNode* node2=node1->next;
            ListNode* cnt=node2;
            for(int i=1;i<k;i++){
                if(cnt==nullptr) return dummy->next;
                cnt=cnt->next;
            }
            for(int i=1;i<k;i++){
                node1->next=node2->next;
                node2->next=node0->next;  //node0->next始终指向当前链表的头部
                node0->next=node2;
                node2=node1->next;
            }
            node0=node1;
            node1=node0->next;
        }
        return dummy->next;
    }
};

11.随机链表的复制

        哈希映射法建立新链表结点与原节点的映射关系。

class Solution {
public:
    unordered_map<Node*,Node*> map;  //存储原链表节点到新链表节点的映射
    Node* copyRandomList(Node* head) {
        if(!head) return nullptr;
        //检查当前节点是否已经在哈希表中(即是否已经被复制过)
        //如果节点未被复制过,则创建一个新节点,值与原节点相同,并将原节点和新节点的映射存入哈希表
        if(!map.count(head)){
            Node* newHead=new Node(head->val);
            map[head]=newHead;
            //递归复制next指针指向的链表部分和random指针指向的节点
            newHead->next=copyRandomList(head->next);
            newHead->random=copyRandomList(head->random);
        }
        return map[head];  //返回头结点在新链表中的映射
    }
};

12.排序链表

        类似归并排序方法,先二分找到中点(通过快慢指针法),再对左右两边分别排序,最后合并两部分。

class Solution {
    // 链表的中间结点(快慢指针)
    ListNode* middleNode(ListNode* head) {
        ListNode* pre=head;
        ListNode* slow=head;
        ListNode* fast=head;
        while (fast&&fast->next) {
            pre=slow; // 记录 slow 的前一个节点
            slow=slow->next;
            fast=fast->next->next;
        }
        pre->next=nullptr; // 断开 slow 的前一个节点和 slow 的连接
        return slow;  // 链表后半部分
    }
    // 合并两个有序链表(双指针),归并思想
    ListNode* merge(ListNode* list1, ListNode* list2) {
        ListNode dummy; // 用哨兵节点简化代码逻辑
        ListNode* cur=&dummy; // cur 指向新链表的末尾
        while(list1&&list2){
            if(list1->val<=list2->val){
                cur->next=list1; // 把 list1 加到新链表中
                list1=list1->next;
            } 
            else{ 
                cur->next=list2;
                list2=list2->next;
            }
            cur=cur->next;
        }
        cur->next=list1?list1:list2; // 拼接剩余链表
        return dummy.next;
    }
public:
    ListNode* sortList(ListNode* head) {
        if (!head||!head->next) return head;
        // 找到中间节点 head2,并断开 head2 与其前一个节点的连接,然后分治、合并
        // 比如 head=[4,2,1,3],那么 middleNode 调用结束后 head=[4,2] head2=[1,3]
        ListNode* head2 = middleNode(head);
        head=sortList(head);
        head2=sortList(head2);
        return merge(head, head2);
    }
};

13.合并k个升序链表

        利用小根堆实现,小根堆里维护每个非空链表未被处理的第一个结点

class Solution {
public:
    ListNode* mergeKLists(vector<ListNode*>& lists) {
        struct Cmp{
            bool operator()(ListNode* a, ListNode* b){
                return a->val>b->val;
            }
        };
        priority_queue<ListNode*,vector<ListNode*>,Cmp> min_heap;  //优先队列模拟小根堆
        for(ListNode* node:lists){
            if (node) min_heap.push(node);  //把所有非空链表的头结点入堆 
        }
        ListNode dummy(0);  
        ListNode* tail=&dummy;  //tail负责维护合并后的新链表
        while(!min_heap.empty()){
            ListNode* min_node=min_heap.top();  //剩余结点中的最小结点
            min_heap.pop(); 
            if(min_node->next) min_heap.push(min_node->next);
            tail->next=min_node;  //把min_node添加到新链表末尾
            tail=tail->next;  //准备合并下一个结点
        }
        return dummy.next;
    }
};

14.LRU缓存

struct DLinkedNode {
    int key, value;
    DLinkedNode* prev;
    DLinkedNode* next;
    DLinkedNode():key(0),value(0),prev(nullptr),next(nullptr){}
    DLinkedNode(int _key,int _value):key(_key),value(_value),prev(nullptr),next(nullptr){}
};
class LRUCache {
private:
    unordered_map<int, DLinkedNode*> cache;
    DLinkedNode* head;
    DLinkedNode* tail;
    int size;
    int capacity;
public:
    LRUCache(int _capacity): capacity(_capacity), size(0) {
        // 使用伪头部和伪尾部节点
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head->next=tail;
        tail->prev=head;
    }
    int get(int key){
        if(!cache.count(key)) return -1;
        // 如果 key 存在,先通过哈希表定位,再移到头部
        DLinkedNode* node=cache[key];
        moveToHead(node);
        return node->value;
    }
    void put(int key, int value) {
        if (!cache.count(key)) {
            // 如果 key 不存在,创建一个新的节点
            DLinkedNode* node = new DLinkedNode(key, value);
            // 添加进哈希表
            cache[key] = node;
            // 添加至双向链表的头部
            addToHead(node);
            size++;
            if(size>capacity) {
                // 如果超出容量,删除双向链表的尾部节点
                DLinkedNode* removed = removeTail();
                // 删除哈希表中对应的项
                cache.erase(removed->key);
                // 防止内存泄漏
                delete removed;
                size--;
            }
        }
        else {
            // 如果 key 存在,先通过哈希表定位,再修改 value,并移到头部
            DLinkedNode* node = cache[key];
            node->value = value;
            moveToHead(node);
        }
    }
    void addToHead(DLinkedNode* node) {
        node->prev=head;
        node->next=head->next;
        head->next->prev=node;
        head->next=node;
    }
    void removeNode(DLinkedNode* node) {
        node->prev->next=node->next;
        node->next->prev=node->prev;
    }
    void moveToHead(DLinkedNode* node){
        removeNode(node);
        addToHead(node);
    }
    DLinkedNode* removeTail(){
        DLinkedNode* node=tail->prev;
        removeNode(node);
        return node;
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2400678.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

6. MySQL基本查询

1. 表的增删改查 Create(创建), Retrieve(读取), Update(更新), Delete(删除) 2. Create & Insert 语法: insert [info] table_name () values () 2.1. 案例: 创建一个学生表 指定列单行插入, 如果values前省略, 则默认是全属性插入多行指定列插入, 中间分隔符为, 3. 插入替…

CMS32M65xx/67xx系列CoreMark跑分测试

CMS32M65xx/67xx系列CoreMark跑分测试 1、参考资料准备 1.1、STM32官方跑分链接 1.2、官网链接 官方移植文档&#xff0c;如下所示&#xff0c;点击红框处-移植文档: A new whitepaper and video explain how to port CoreMark-Pro to bare-metal 1.3、测试软件git下载链接 …

中国区域30m/15天植被覆盖度数据集(2010-2022)

时间分辨率&#xff1a;日空间分辨率&#xff1b;&#xff1a;10m - 100m共享方&#xff1a;式开放获取数据大小&#xff1a;2.98 TB数据时间范围&#xff1a;2010-01-01 — 2022-12-31元数据更新时间&#xff1a;2024-12-23 数据集摘要 高时空分辨率的植被覆盖度产品存在着广…

力扣HOT100之二分查找:74. 搜索二维矩阵

这道题直接a了&#xff0c;我们可以参考上一道题&#xff1a;35.搜索插入位置的思路&#xff0c;详情见我的上一篇博客。将每一行的第一个元素当作一个数组中的元素&#xff0c;然后对这个数组进行二分查找&#xff0c;如果直接找到了target&#xff0c;则直接返回true&#xf…

编程技能:格式化打印04,sprintf

专栏导航 本节文章分别属于《Win32 学习笔记》和《MFC 学习笔记》两个专栏&#xff0c;故划分为两个专栏导航。读者可以自行选择前往哪个专栏。 &#xff08;一&#xff09;WIn32 专栏导航 上一篇&#xff1a;编程技能&#xff1a;格式化打印03&#xff0c;printf 回到目录…

R语言基础| 下载、安装

在此前的单细胞教程中&#xff0c;许多小伙伴都曾因为R语言基础不足而十分苦恼。R语言是一种开源的编程语言和软件环境&#xff0c;专门用于统计分析、图形表示和数据挖掘。它最初由Ross Ihaka和Robert Gentleman在1993年创建&#xff0c;旨在为统计学家和数据分析师提供一个广…

微软的新系统Windows12未来有哪些新特性

在今年即将到来的重大设计升级中,苹果计划对其全线操作系统统一按年份命名,作为另一巨头微软的win12还远吗?win11和win10是微软现在正在用的主流版本,win11系统发布于2021年6月24日,win10系统发布于2015年7月29日。预计win12尝鲜版可能在2025年下半年或明年。 尽管win12还…

在虚拟宇宙中低语——进程间通信,Linux命名管道的前世今生

文章目录 &#x1f30c; 序章&#x1f320; 一、命名管道的宿命与哲学1.1、创建及简单使用1.2、命名管道的工作原理1.3、命名管道与匿名管道的区别 2、命名管道的特点及特殊场景2.1、特点2.2、四种特殊场景 3、命名管道实操3.1、实现文件拷贝3.2、实现进程控制 小结 &#x1f3…

STM32的ADC简介

一、ADC简介 STM32的ADC是一种12位逐次逼近型模拟数字转换器。它具备18个通道&#xff0c;能够测量16个外部信号源以及2个内部信号源。各通道的A/D转换可以执行单次、连续、扫描或间断模式。转换结果可采用左对齐或右对齐的方式&#xff08;12位&#xff09;存储于16位数据寄存…

Bash shell四则运算

文章目录 四则运算1. ‌expr 命令‌2. ‌$(( )) 表达式&#xff08;推荐&#xff09;‌3. ‌$[ ] 表达式&#xff08;已弃用&#xff09;‌4. ‌let 命令‌小数运算i 和 i 区别 四则运算 算术运算&#xff1a; - * / %&#xff08;取模&#xff0c;求余数&#xff09; Bash sh…

(javaSE)Java数组进阶:数组初始化 数组访问 数组中的jvm 空指针异常

数组的基础 什么是数组呢? 数组指的是一种容器,可以用来存储同种数据类型的多个值 数组的初始化 初始化&#xff1a;就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。 数组初始化的两种方式&#xff1a;静态初始化&#xff0c;动态初始化 数组的静态初始化 初始化…

力扣刷题Day 70:在排序数组中查找元素的第一个和最后一个位置(34)

1.题目描述 2.思路 方法1&#xff08;自己写的&#xff09;&#xff1a;一次二分查找找到等于target的一个元素索引axis&#xff0c;然后向左右延伸找边界。 方法2&#xff08;灵茶山艾府佬的闭区间二分查找写法&#xff09;&#xff1a;定义一个lower_bound()函数找到第一个…

图片压缩工具 | 图片属性详解及读取解析元数据

ℹ️ 图片信息及属性 基本属性 格式类型&#xff1a;JPEG、PNG、GIF、WEBP、BMP、TIFF等文件大小&#xff1a;以KB、MB等为单位的存储空间占用创建/修改日期&#xff1a;文件的元数据时间戳 视觉属性 尺寸/分辨率 宽度&#xff08;像素&#xff09;高度&#xff08;像素&…

C# Onnx 动漫人物人脸检测

目录 效果 模型信息 项目 代码 下载 参考 效果 模型信息 Model Properties ------------------------- stride&#xff1a;32 names&#xff1a;{0: face} --------------------------------------------------------------- Inputs ------------------------- name&am…

C++内存列传之RAII宇宙:智能指针

文章目录 1.为什么需要智能指针&#xff1f;2.智能指针原理2.1 RAll2.2 像指针一样使用 3.C11的智能指针3.1 auto_ptr3.2 unique_ptr3.3 shared_ptr3.4 weak_ptr 4.删除器希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力&#xff01; 智能指针是 C 中用于自动…

PVE 虚拟机安装 Ubuntu Server V24 系统 —— 一步一步安装配置基于 Ubuntu Server 的 NodeJS 服务器详细实录1

前言 最近在基于 NodeJS V22 写一个全栈的项目&#xff0c;写好了&#xff0c;当然需要配置服务器部署啦。这个过程对于熟手来说&#xff0c;还是不复杂的&#xff0c;但是对于很多新手来说&#xff0c;可能稍微有点困难。所以&#xff0c;我把整个过程全部记录一下。 熟悉我…

TDengine 开发指南——高效写入

高效写入 本章内容将介绍如何发挥 TDengine 最大写入性能&#xff0c;通过原理解析到参数如何配置再到实际示例演示&#xff0c;完整描述如何达到高效写入。 为帮助用户轻松构建百万级吞吐量的数据写入管道&#xff0c;TDengine 连接器提供高效写入的特性。 启动高效写入特性…

Linux kill 暂停命令

暂停进程 kill -19 在一台服务器上部署了360Pika服务&#xff0c;先用RedisClient连接一下&#xff0c;可以连接 现在暂停进程 暂停后发现再次连接无法连接 恢复进程 kill -18 恢复后可连接

2.0 阅读方法论与知识总结

引言 本文将详细分析考研英语阅读做题步骤&#xff0c;并对方法论进行总结&#xff0c;最后通过真题练习巩固方法。 一、做题步骤 所有技巧都建立在精读真题的基础上&#xff01;建议按以下节奏复习&#xff1a; 1️⃣ 做题 先看题干了解文章大致主旨&#xff08;看看有没有…

5. Qt中.pro文件(1)

本节主要讲.pro文件的作用和一些相关基础知识与操作。 本文部分ppt、视频截图原链接&#xff1a;[萌马工作室的个人空间-萌马工作室个人主页-哔哩哔哩视频] 1 PRO文件 1.1 pro文件作用 添加需要用到的QT模块&#xff0c;如通过QT module_name来添加需要用到的Qt模块。指定生…