LeetCode经典题之876、143 题解及延伸

系列目录

88.合并两个有序数组
52.螺旋数组
567.字符串的排列
643.子数组最大平均数
150.逆波兰表达式
61.旋转链表
160.相交链表
83.删除排序链表中的重复元素
389.找不同
1491.去掉最低工资和最高工资后的工资平均值
896.单调序列
206.反转链表
92.反转链表II
141.环形链表
142.环型链表


目录

  • 系列目录
  • 876. 链表的中间节点
    • 线性表
  • 143. 重排链表
    • push_back()与emplace_back()
      • push_back()
      • emplace_back()


876. 链表的中间节点

🌟线性表/动态数组+快慢指针

原题链接


C++
若未特殊标明,以下题解均写用C++

方法一 快慢指针
/**
 * 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* middleNode(ListNode* head) {
        ListNode *slow = head, *fast = head;
        // 记得一定要先对fast 进行检查
        while (fast != nullptr && fast->next != nullptr) {
            slow = slow->next;
            fast = fast->next->next;
        }

        return slow;
    }
};

先检查 fast 是为了确保在尝试访问 fast->next 之前,fast 不是 nullptr,从而可以避免未定义行为


方法二 线性表/动态数组
/**
 * 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* middleNode(ListNode* head) {
        // 定义一个类似于数组特性的线性表——支持下标访问
        vector<ListNode*> a = {head};
        // a.back()取原线性表的最后一个元素
        while (a.back()->next != nullptr)
            a.push_back(a.back()->next);
        
        // C++ 默认向下取整
        return a[a.size() / 2];
    }
};

注解:

vector<ListNode*> a = {head};

vector的元素为链表的节点ListNode*——这也是我们为什么要nullptr的原因

并创建一个包含单个元素(即head指针)的vector

若没有{head},则定义的是一个空的容器vector


线性表

定义

  • 线性表(Linear List)是数据结构的一种,它是一个具有相同特性的数据元素的有限序列
  • 数据元素之间的关系是一对一的,即除了第一个和最后一个数据元素之外,其他数据元素都是首尾相接的
  • 线性表的个数n定义为线性表的长度,n=0时称为空表

性质

  1. 集合中必存在唯一的一个“第一元素”:线性表有明确的起始点
  2. 集合中必存在唯一的一个“最后元素”:线性表有明确的终止点
  3. 除最后一个元素之外,均有唯一的后继(后件):除了最后一个元素,每个元素后面都跟着一个元素
  4. 除第一个元素之外,均有唯一的前驱(前件):除了第一个元素,每个元素前面都有一个元素
  5. 线性表能够逐项访问和顺序存取:可以按照元素的顺序进行访问和存储

分类

  • 一般线性表:可以自由地进行删除或添加操作
  • 受限线性表:主要包括栈(后进先出)和队列(先进先出),对结点的操作有限制

基本操作

  1. MakeEmpty(L):将L变为空表
  2. Length(L):返回表L的长度,即表中元素个数
  3. Get(L, i):返回L中位置i处的元素(1≤i≤n)
  4. Prior(L, i):取i的前驱元素
  5. Next(L, i):取i的后继元素
  6. Locate(L, x):返回元素x在L中的位置
  7. Insert(L, i, x):在表L的位置i处插入元素x,将原占据位置i的元素及后面的元素都向后推一个位置
  8. Delete(L, p):从表L中删除位置p处的元素
  9. IsEmpty(L):判断L是否为空表

应用场景

  • 通讯录管理:每个联系人作为线性表的一个元素,包含姓名、电话号码、地址等属性
  • 缓存替换算法:如最近最少使用算法(LRU)和先进先出算法(FIFO),使用线性表结构便于对缓存中的数据进行插入、删除和查找操作
  • 任务调度系统:将需要执行的任务按照一定的优先级顺序存储在线性表中
  • 计算机图形学:顶点表用于存储图形模型的顶点信息,每个元素表示一个顶点
  • 公交线路查询系统:线路信息可以用线性表来存储,每个线路作为线性表的一个元素

优点

  • 逻辑结构简单,便于实现和操作
  • 广泛应用于各种实际场景中,是数据处理和存储的基础结构之一





143. 重排链表

🌟线性表/动态数组

原题链接


C++
若未特殊标明,以下题解均写用C++

/**
 * 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:
    void reorderList(ListNode* head) {
        // 特况
        if (head == nullptr) 
            return;
        
        // 定义一个空线性表 Linear List
        vector<ListNode*> LL;
        ListNode* node = head;
        // 将 链表节点 存入 线性表中
        while (node != nullptr) {
            LL.emplace_back(node);
            node = node->next;
        }

        // 下标从0开始
        int i = 0, j = LL.size() - 1;
        while (i < j) {
            // 像数组一样 可用下标访问
            LL[i]->next = LL[j];
            i ++;
            
            // 如LL.size() = 2,提前结束循环
            if (i == j)
                break;

            LL[j]->next = LL[i];
            // 用完 j 再更新
            j --;
        }

        
        // 最后别忘了 指向空
        LL[i]->next = nullptr;
    }
};

push_back()与emplace_back()

push_back()

push_backstd::vector 的一个成员函数,用于在容器的末尾添加一个元素 当你使用 push_back 时,你需要提供一个与容器内元素类型相同的对象(或者一个可以隐式转换为该类型的对象) 这个对象会被复制(如果类型支持复制)或移动(如果类型支持移动并且提供了右值引用)到容器的末尾

示例:

#include <vector>  
#include <string>  
  
int main() {  
    std::vector<std::string> vec;  
  
    // 使用 push_back 添加一个字符串  
    std::string str = "Hello";  
    vec.push_back(str); // 这里可能发生复制或移动操作  
  
    // 也可以直接使用临时对象  
    vec.push_back(std::string("World")); // 这里一定会发生复制操作(因为我们是用一个右值来初始化一个临时对象)  
  
    return 0;  
}

在上面的例子中,当你使用 push_back 并传递一个 std::string 对象时,如果 str 是一个左值(即具有持久身份的对象),那么它可能会被复制或移动(取决于 std::string 的实现和编译器优化) 如果你传递一个右值(如临时对象),那么通常会发生复制操作,因为右值通常不被视为可移动的对象(尽管在某些情况下,编译器可能会进行优化以消除不必要的复制)


emplace_back()

emplace_back 是 C++11 引入的一个成员函数,旨在提供比 push_back 更高的性能 与 push_back 不同,emplace_back 允许你直接在容器的末尾构造一个元素,而不是先创建一个对象然后将其复制或移动到容器中 这通常可以避免不必要的复制或移动操作,尤其是在处理大型或复杂的对象时

emplace_back 接受与要构造的对象构造函数相同的参数,并在容器的末尾直接调用该构造函数

示例:

#include <vector>  
#include <string>  
  
int main() {  
    std::vector<std::string> vec;  
  
    // 使用 emplace_back 直接在容器末尾构造一个字符串  
    vec.emplace_back("Hello"); // 直接在vec的末尾构造一个std::string对象,没有复制或移动  
  
    // 也可以传递多个参数给构造函数  
    vec.emplace_back(5, 'a'); // 构造一个包含5个'a'字符的std::string对象  
  
    return 0;  
}

在上面的例子中,emplace_back 直接在 vec 的末尾构造了一个 std::string 对象,没有涉及任何复制或移动操作
这通常比使用 push_back 并传递一个临时对象更高效

总结:

push_backemplace_back 都用于在 std::vector 的末尾添加元素,但 emplace_back 通过直接在容器中构造元素来避免不必要的复制或移动操作,从而可能提供更高的性能

虽然 emplace_back 通常比 push_back 更高效,但在某些情况下(特别是当元素类型支持移动语义且移动操作比复制操作更快时),push_back 可能会使用移动操作来优化性能
然而,emplace_back 仍然是一个很好的选择,特别是当对象的构造过程涉及多个参数或复杂逻辑时

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux】静态库、动态库

动静态库里面包含的是源文件通过汇编阶段生成的后缀为.o的可重定位目标文件。我们在使用C语言&#xff0c;包含一个stdio.h头文件就可以使用scanf方法&#xff0c;其实都是系统调用了相应的头文件和库&#xff0c;库里面有开发者已经写好各种方法。也就是说我们在使用C语言时&a…

Java | Leetcode Java题解之第191题位1的个数

题目&#xff1a; 题解&#xff1a; public class Solution {public int hammingWeight(int n) {int ret 0;while (n ! 0) {n & n - 1;ret;}return ret;} }

【学习】软件测试中常见的文档类型及其作用

在软件开发的生命周期中&#xff0c;软件测试是确保产品质量的关键步骤。为了系统地进行测试活动&#xff0c;并保证测试结果的有效性和可追溯性&#xff0c;产生了一系列标准化的测试文档。这些文档不仅为测试人员提供了执行指南&#xff0c;而且为项目管理者和利益相关者提供…

【排序 队列】1585. 检查字符串是否可以通过排序子字符串得到另一个字符串

本文涉及知识点 排序 队列 LeetCode1585. 检查字符串是否可以通过排序子字符串得到另一个字符串 给你两个字符串 s 和 t &#xff0c;请你通过若干次以下操作将字符串 s 转化成字符串 t &#xff1a; 选择 s 中一个 非空 子字符串并将它包含的字符就地 升序 排序。 比方说&a…

Discourse 的 AI 内容分享

虽然 Discourse 的 AI 接口调用是需要比较高的用户权限或者管理员权限。 但是对已经生成的结果&#xff0c;Discourse 是可以保存并且分享的。 例如&#xff0c;我们搜索了一些美食的做法。 在页面的下面有一个分享 AI 对话的按钮。 在随后弹出的界面中&#xff0c;会又一个…

服务运营 | MS文章精选:线上点单,当真免排队?餐饮零售与医疗场景中的全渠道运营

编者按&#xff1a; 小A走进了一家奶茶店&#xff0c;准备向店员点单&#xff0c;但却在屏幕上看到还有98杯奶茶待制作&#xff08;因为线上订单突然暴增&#xff09;。因此&#xff0c;小A不满地嘟囔着离开了奶茶店。这个例子展示了线上渠道可能会对线下渠道造成一些负面影响…

链表数组遍历输出的辨析(二者都含指针的情况下)----PTA期末复习题

输入输出三位学生的学号和信息 一开始我认为是指针&#xff0c;直接背了指针输出的方式&#xff1b;p;p!NULL;pp->next 这个是错误的 下面这个输出是正确的方式 分析怎么区分这两个 举个例子来 数组遍历&#xff1a; 链表遍历&#xff1a; 输出的结果&#xff1a; 如果将…

第十次作业

1.登陆界面 2.导航页面 3.接口&#xff08;我负责的主要是管理员管理用户和密码的界面&#xff09; import request from /utils/request// 登录 export function login(data) {return request({url: /user/login,method: post,data}) }// 获取用户信息 export function getIn…

网关登录校验

如何在网关转发之前做登录校验&#xff1f; 网关请求处理流程 如何在网关转发之前做登录校验&#xff1f; 网关如何将用户信息传递给微服务&#xff1f; 如何在微服务之间传递用户信息&#xff1f; 自定义过滤器 网关过滤器有两种&#xff0c;分别是&#xff1a; GatewayFi…

春秋云境:CVE-2022-25411[漏洞复现]

根据题目提示和CNNVD优先寻找后台管理地址 靶机启动后&#xff0c;使用AWVS进行扫描查看网站结构 在这里可以看到后台管理的登录地址&#xff1a;/admin/&#xff0c;根据题目提示可知是弱口令 尝试admin、123456、admin666、admin123、admin888...等等常见弱口令 正确的账户…

论文导读 | Manufacturing Service Operations Management近期文章精选

编者按 在本系列文章中&#xff0c;我们梳理了顶刊Manufacturing & Service Operations Management5月份发布有关OR/OM以及相关应用的文章之基本信息&#xff0c;旨在帮助读者快速洞察行业/学界最新动态。 推荐文章1 ● 题目&#xff1a;Robust Drone Delivery with Weath…

KVM网络模式设置

一、KVM网络模式介绍 1、NAT ( 默认上网 ) 虚拟机利用host机器的ip进行上网,对外显示一个ip;virbr0是KVM 默认创建的一个 Bridge,其作用是为连接其上的虚机网卡提供NAT访问外网的功能,默认ip为192.168.122.1 2、自带的Bridge 将虚拟机桥接到host机器的网卡上,vm和ho…

【C++题解】1712. 输出满足条件的整数2

问题&#xff1a;1712. 输出满足条件的整数2 类型&#xff1a;简单循环 题目描述&#xff1a; 有这样的三位数&#xff0c;其百位、十位、个位的数字之和为偶数&#xff0c;且百位大于十位&#xff0c;十位大于个位&#xff0c;请输出满所有满足条件的整数。 输入&#xff1…

C++ | Leetcode C++题解之第191题位1的个数

题目&#xff1a; 题解&#xff1a; class Solution { public:int hammingWeight(uint32_t n) {int ret 0;while (n) {n & n - 1;ret;}return ret;} };

SpringBoot控制反转和依赖注入

目录 一、内聚和耦合 二、分层解耦 三、具体实现 四、bean的组件扫描 五、bean注入 一、内聚和耦合 在了解分层解耦的概念之前我们我们要去先了解一下内聚和耦合。内聚&#xff1a;通常将的是软件中各个模块之间的功能联系。耦合衡量软件各个模块之间的依赖、关联的程度。一…

【ai】tx2 nx : fix pip升级警告

jetson 环境同样出现:【原创】pip3 使用报警问题在对 Ubuntu 18.04 上的 pip3 9.0.1 版本使用 pip install -U pip 的方式进行升级后,再使用 pip 就会出现一堆警告信息。这个警告信息目前不影响使用,但从警告信息来看,会在未来版本中出现失败风险。 当前系统中存在了两个不…

Android反编译之Apktool

文章目录 简述工具操作步骤 简述 可以从apk安装包中提取出res、AndroidManifest、xml等文件&#xff1b;也可以修改资源文件后rebuild一个apk。 工具 1.官方下载地址 https://apktool.org/ 2.操作指令 // 解析apk包 $ apktool d test.apk // 重新rebuid apk包 $ apktool …

vscode_cmake_stm32_lvgl移植及显示优化

1 LVGL移植 本文使用的环境如下&#xff1a; STM32H743FreeRTOSst7789 lcd(320*240) 下载 LVGL源码&#xff0c;本文使用Release v9.1.0&#xff1b; 将压缩包解压到工程目录&#xff0c;例如stm32h7xx_cmake_project/components/lvgl-9.1.0&#xff0c;如下所示&#xff1a; …

vue3封装表格嵌套表单问题汇总

1.插槽嵌套多层数据ui组件怎么使用 思路&#xff1a;插槽具名【区分】后暴露传递&#xff0c;这个为神魔要区分&#xff0c;因为封装组件表格列表项也有插槽 步骤一&#xff1a;表单插槽暴露 <ElFormclass"form-search":model"formParams"ref"form…

Linux 磁盘挂载与分区

Linux 磁盘挂载与分区 vda1: 其中vd表示虚拟磁盘&#xff0c;a表示第一块磁盘&#xff0c;b表示第二块磁盘&#xff0c;1表示第一块磁盘的第一分区&#xff08;显然两块磁盘都只有一个分区&#xff09;图中可以看到&#xff0c;vda1磁盘只有一个分区&#xff0c;且全部挂载到根…