leetcode 1766

leetcode 1766

题目

在这里插入图片描述

例子

在这里插入图片描述

思路

将边的关系,转化为树结构。
记录val 对应的id 列表。
记录是否遍历过节点。
记录id 和对应的深度。

使用dfs, 从根开始遍历。

代码实现

class Solution {
private:
    vector<vector<int>> gcds;

    //val : the id of nodes matching the val 
    vector<vector<int>> val_to_id;
    // i-th node : parent and childern of i-th node
    vector<vector<int>> graph;
    //i-th node : depth of i-th node
    vector<int> dep;
    //i-th node : ans of i-th node
    vector<int> ans;

public:

    void dfs(vector<int>& nums, int id, int depth){
        dep[id] = depth;

        for(int val : gcds[nums[id]]){
            if(val_to_id[val].empty()){
                //dfs 当前深度,找不到对应的gcd的值
                continue;
            }else{
                //获取已经遍历的节点的val的对应的id, 从根开始记录val_to_id的列表,所以back应该是最近的节点。
                int last_id = val_to_id[val].back();
                if(ans[id] == -1 || dep[last_id] > dep[ans[id]]){
                    ans[id] = last_id;
                }
            }
        }

        val_to_id[nums[id]].push_back(id);

        for(int child_id : graph[id]){
            //等于-1没有遍历过
            if(dep[child_id] == -1){
                dfs(nums, child_id, depth +1);
            }
        }

        val_to_id[nums[id]].pop_back();


    }

    vector<int> getCoprimes(vector<int>& nums, vector<vector<int>>& edges) {
        int n = nums.size();

        gcds.resize(51);
        val_to_id.resize(51);

        ans.resize(n, -1);
        dep.resize(n, -1);
        graph.resize(n);

        for(int i=1; i<= 50; i++){
            for(int j=1; j<= 50; j++){
                if(gcd(i,j) == 1){
                    gcds[i].push_back(j);
                }
            }
        }

        for(const auto& val : edges){
            // 无向图,根据dep[id] 是否为-1, 判断是否遍历
            graph[val[0]].push_back(val[1]);
            graph[val[1]].push_back(val[0]);
        }

        dfs(nums, 0, 1);

        return ans;
    }
};

push_back 和 pop_back

push_back()pop_back()std::vector 容器类提供的两个重要成员函数,用于向向量尾部添加元素和删除尾部元素。

push_back()

push_back() 函数用于在 vector 的末尾添加一个新元素。它将新元素插入到向量的尾部,使得向量的大小增加 1。语法如下:

void push_back(const T& value);
void push_back(T&& value);

其中,value 是要添加到向量末尾的元素。如果 vector 的存储空间不足以容纳新元素,push_back() 函数会自动重新分配更大的存储空间,并将元素添加到向量的末尾。示例如下:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec;

    // 添加元素到向量尾部
    vec.push_back(10);
    vec.push_back(20);
    vec.push_back(30);

    // 打印向量的元素
    for (int num : vec) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出为:

10 20 30

pop_back()

pop_back() 函数用于删除 vector 的末尾元素,减小向量的大小。它不会返回任何值。如果 vector 不为空,则会删除最后一个元素;如果 vector 为空,则调用 pop_back() 函数会导致未定义行为。语法如下:

void pop_back();

示例:

#include <iostream>
#include <vector>

int main() {
    std::vector<int> vec = {10, 20, 30};

    // 删除向量的最后一个元素
    vec.pop_back();

    // 打印向量的元素
    for (int num : vec) {
        std::cout << num << " ";
    }
    std::cout << std::endl;

    return 0;
}

输出为:

10 20

在使用 pop_back() 函数之前,通常应该检查 vector 是否为空,以避免未定义行为。

这些函数是 std::vector 容器类的基本操作之一,非常常用于动态管理序列的大小和内容。

容器

在 C++ 中,容器是用来存储和管理一组对象的数据结构。标准模板库(STL)提供了多种容器,每种容器都有自己的特点和适用场景。以下是 C++ 中常用的几种容器:

  1. Vector(向量)

    • 动态数组,大小可以动态增长。
    • 支持快速随机访问。
    • 在尾部插入元素的开销低,但在中间或头部插入元素的开销较高。
    • 适合需要频繁对尾部进行插入和删除操作的场景。
  2. Deque(双端队列)

    • 双端队列,支持在两端高效地进行插入和删除操作。
    • 比向量更适合在两端进行频繁的插入和删除操作。
  3. List(链表)

    • 双向链表,支持在任意位置高效地进行插入和删除操作。
    • 不支持随机访问,访问元素的时间复杂度为 O(n),而在头部和尾部插入和删除元素的时间复杂度为 O(1)。
  4. Forward List(前向链表)

    • 单向链表,与双向链表相比,每个节点只保存下一个节点的地址。
    • 支持在链表头部高效地进行插入和删除操作,但不支持在链表尾部直接访问。
  5. Stack(栈)

    • 后进先出(LIFO)的数据结构,只允许在栈顶进行插入和删除操作。
    • 基于向量或双端队列实现。
  6. Queue(队列)

    • 先进先出(FIFO)的数据结构,只允许在队尾插入元素,在队头删除元素。
    • 基于双端队列实现。
  7. Priority Queue(优先队列)

    • 元素按照一定的优先级顺序排列,每次取出优先级最高的元素。
    • 基于堆(heap)实现。
  8. Set(集合)

    • 不重复元素的集合,通常基于红黑树实现。
    • 支持高效的插入、删除和查找操作,元素按照升序排序。
  9. Multiset(多重集合)

    • 允许重复元素的集合,通常基于红黑树实现。
    • 元素按照升序排序。
  10. Map(映射)

    • 键值对的集合,每个键唯一对应一个值。
    • 支持高效的插入、删除和查找操作,键按照升序排序。
  11. Multimap(多重映射)

    • 键可以重复的映射。
    • 键按照升序排序。

这些容器都位于标准命名空间 std 中,可以通过包含相应的头文件来使用它们,例如 <vector><list><stack> 等。每种容器都有自己的优势和适用场景,选择合适的容器取决于具体的需求和性能要求。

push_back 函数

  1. void push_back(const T& value);:这个函数接受一个常量引用作为参数。当调用这个函数时,它会复制参数 value 的值,并将这个值添加到容器的末尾。这意味着在函数调用过程中会发生数据的复制操作,因为它是通过常量引用传递的,所以不会改变传递给函数的实参。

    std::vector<int> vec;
    int x = 10;
    vec.push_back(x); // 使用常量引用版本,复制 x 的值到容器
    
  2. void push_back(T&& value);:这个函数接受一个右值引用作为参数。当调用这个函数时,它会使用参数 value 的值,并将其添加到容器的末尾。这个版本的函数通常用于移动语义,它不会复制参数的值,而是窃取参数的资源(例如,移动对象的所有权),因此更高效。

    std::vector<std::string> vec;
    std::string str = "Hello";
    vec.push_back(std::move(str)); // 使用右值引用版本,窃取 str 的资源到容器
    

下面是两个版本的使用示例:

#include <iostream>
#include <vector>
#include <string>

int main() {
    // 使用常量引用版本
    std::vector<int> vec1;
    int x = 10;
    vec1.push_back(x); // 复制 x 的值到容器
    std::cout << "vec1 size: " << vec1.size() << std::endl;

    // 使用右值引用版本
    std::vector<std::string> vec2;
    std::string str = "Hello";
    vec2.push_back(std::move(str)); // 窃取 str 的资源到容器
    std::cout << "vec2 size: " << vec2.size() << std::endl;

    return 0;
}

在这个例子中,push_back(const T& value) 将会复制 x 的值到容器 vec1 中,而 push_back(T&& value) 则会窃取 str 的资源到容器 vec2 中。

引用

在 C++ 中,引用与传递地址有些相似,但并不完全等同。引用本质上是一个别名,它是被绑定到另一个对象或变量上的名称。当你使用引用时,实际上是在操作原始对象,而不是它的地址。

与传递地址不同的是,引用不需要进行解引用操作(使用指针时需要使用解引用操作符 *),因为引用本身就是原始对象的别名,所以操作起来更加直观和方便。

另外,使用引用传递参数时,不会涉及指针的语法,从而减少了一些错误的可能性,例如空指针引用等。同时,引用在编译期间会进行类型检查,从而提供了更强的类型安全性。

因此,虽然引用有些类似于传递地址的概念,但它们之间有着明显的区别。

引用传递是一种在函数参数中使用引用的机制,允许函数直接访问并修改调用者提供的变量。通过引用传递,可以避免复制大型对象,提高程序的性能并减少内存使用。

在C++中,引用传递通常通过引用参数实现,有两种类型的引用参数:

  1. 左值引用(Lvalue Reference):通过使用 & 符号声明的引用类型。左值引用可以绑定到具有名称的变量,包括对象、数组、函数等。在函数中修改左值引用的值会影响到调用者提供的原始变量。

    void modifyValue(int& x) {
        x += 10;
    }
    
    int main() {
        int num = 5;
        modifyValue(num);
        std::cout << "Modified value: " << num << std::endl; // 输出 15
        return 0;
    }
    
  2. 右值引用(Rvalue Reference):通过使用 && 符号声明的引用类型。右值引用通常用于移动语义,允许将资源(如临时对象)的所有权从一个对象转移给另一个对象。

    void modifyValue(int&& x) {
        x += 10;
    }
    
    int main() {
        modifyValue(5); // 临时对象的所有权转移给函数
        return 0;
    }
    

引用传递相比于值传递有以下优点:

  • 避免对象的复制:使用引用传递可以避免复制大型对象,从而提高程序的性能和效率。
  • 直接修改原始值:通过引用传递,函数可以直接修改调用者提供的变量的值,而无需返回值。

需要注意的是,引用传递可能会导致函数的行为不易理解,因为函数可以修改原始变量的值。因此,建议在使用引用传递时,对函数的行为进行良好的文档说明,以避免产生混淆。

左值和右值

在C++中,左值(lvalue)和右值(rvalue)是两种用于表示表达式的属性的术语。它们主要与对象的生命周期和可修改性相关联。

  1. 左值(Lvalue)

    • 左值是可以标识并且持久存在于内存中的表达式,通常具有名称或者可以取地址的表达式。
    • 左值表达式可以出现在赋值语句的左边或者右边,因为它们代表着一个确定的内存位置。
    • 例如,变量、数组元素、返回左值引用的函数等都是左值。
  2. 右值(Rvalue)

    • 右值是临时的、一次性的值,通常不具有名称或者不能被取地址。
    • 右值表达式通常是在赋值语句的右边出现,它们表示的是一个临时的、无法被修改的值。
    • 例如,常量、临时变量、返回右值引用的函数等都是右值。

在C++11引入的移动语义中,右值引用允许程序员将资源的所有权从一个对象转移给另一个对象,从而避免不必要的复制操作,提高了程序的性能和效率。

总的来说,左值表示具有名称和持久性的值,而右值表示临时的、一次性的值。右值引用允许有效地管理临时对象的生命周期和资源。

lambda 与引用

当使用 Lambda 表达式时,引用捕获允许在 Lambda 函数体内访问并修改外部作用域的变量。这对于需要在 Lambda 函数内部修改外部作用域变量的情况非常有用。以下是一个简单的 C++11 Lambda 表达式示例,展示了如何使用引用捕获:

#include <iostream>

int main() {
    int x = 10;

    // Lambda 表达式使用引用捕获外部变量 x
    auto lambda = [&x]() {
        // 在 Lambda 函数体内部访问和修改外部变量 x
        std::cout << "Inside lambda, x = " << x << std::endl;
        x += 5;
    };

    std::cout << "Before lambda, x = " << x << std::endl;

    // 调用 Lambda 函数
    lambda();

    std::cout << "After lambda, x = " << x << std::endl;

    return 0;
}

在这个示例中,Lambda 表达式 lambda 捕获了外部变量 x 的引用。Lambda 函数体内部可以访问和修改变量 x 的值。当调用 Lambda 函数后,会输出修改后的 x 值。

输出将会是:

Before lambda, x = 10
Inside lambda, x = 10
After lambda, x = 15

这里,在 Lambda 内部访问的 x 是外部的 x,并且通过引用捕获可以在 Lambda 内部修改外部的变量。

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

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

相关文章

windows如何卸载干净 IDEA

Windows 系统要想彻底卸载 IDEA, 步骤如下&#xff1a; 1、卸载 IDEA 程序 点击屏幕左下角 Windows 图标 -> 设置&#xff1a; 在应用中找到 IDEA, 单击它会出现卸载按钮&#xff0c;点击开始卸载&#xff1a; 勾选第一栏 Delete IntelliJ IDEA 2022.2 caches and local hi…

数字乡村可视化大数据-DIY拖拽式设计

DIY拖拽式大数据自由设计万村乐可视化大数据V1.0 随着万村乐数字乡村系统的广泛使用&#xff0c;我们也接收到了客户的真实反馈&#xff0c;最终在公司的决定下&#xff0c;我们推出了全新的可视化大数据平台V1.0版本&#xff0c;全新的可视化平台是一个通过拖拽配置生成可视化…

从 Oracle 到 MySQL 数据库的迁移之旅

文章目录 引言一、前期准备工作1.搭建新的MySQL数据库2 .建立相应的数据表2.1 数据库兼容性分析2.1.1 字段类型兼容性分析2.1.2 函数兼容性分析2.1.3 是否使用存储过程&#xff1f;存储过程的个数&#xff1f;复杂度&#xff1f;2.1.4 是否使用触发器&#xff1f;个数&#xff…

【前缀积】Leetcode 除自身以外数组的乘积

题目解析 238. 除自身以外数组的乘积 算法讲解 我们可以使用两个空间保存当前位置的左边积和右边积&#xff0c;需要注意的地方初始的dp表需要初始化为1&#xff0c;如果是0则无法得到结果&#xff0c;因为此处是乘法 class Solution { public:vector<int> productEx…

【春秋招专场】央国企——国家电网

国家电网目录 1.公司介绍1.1 业务1.2 组成 2.公司招聘2.1 招聘平台2.2 考试安排2.3 考试内容 3.公司待遇 1.公司介绍 1.1 业务 国家电网公司&#xff08;State Grid Corporation of China&#xff0c;简称SGCC&#xff09;是中国最大的国有企业之一&#xff0c;主要负责中国绝…

第十届 蓝桥杯 单片机设计与开发项目 省赛

第十届 蓝桥杯 单片机设计与开发项目 省赛 输入&#xff1a; 频率信号输入模拟电压输入 输出&#xff08;包含各种显示功能&#xff09;&#xff1a; LED显示SEG显示DAC输出 01 数码管显示问题&#xff1a;数据类型 bit Seg_Disp_Mode;//0-频率显示界面 1-电压显示界面 un…

【Python】Python城乡人口数据分析可视化(代码+数据集)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

STM32仿真例程分享(原理图 代码)

STM32仿真例程分享(原理图 代码) 资料下载地址&#xff1a; stm32仿真: https://url83.ctfile.com/d/45573183-60710029-884629?p7526 (访问密码: 7526)

使用 vue3-sfc-loader 加载远程Vue文件, 在运行时动态加载 .vue 文件。无需 Node.js 环境,无需 (webpack) 构建步骤

加载远程Vue文件 vue3-sfc-loader vue3-sfc-loader &#xff0c;它是Vue3/Vue2 单文件组件加载器。 在运行时从 html/js 动态加载 .vue 文件。无需 Node.js 环境&#xff0c;无需 (webpack) 构建步骤。 主要特征 支持 Vue 3 和 Vue 2&#xff08;参见dist/&#xff09;仅需…

vue数据检测原理

前言 Vue中的数据监听离不开Object.defineProperty()方法的使用&#xff0c;在了解数据监测原理之前&#xff0c;建议先掌握defineProperty的用法。 目标 1 数据监测问题 2 数据监测原理 3 如何实现数组更新 1 遇到的问题 数组更新问题 <button click"updatePeople&q…

Java使用OpenOffice将office文件转换为PDF

Java使用OpenOffice将office文件转换为PDF 1. 先行工作1.1 OpenOffice官网下载1.2 JODConverter官网下载1.3 下载内容 2.介绍3. 安装OpenOffice服务3.1.Windows环境3.2 Linux环境 4. maven依赖5. 转换代码 1. 先行工作 请注意&#xff0c;无论是windows还是liunx环境都需要安装…

第6章 6.3 正则表达式(MATLAB入门课程)

讲解视频&#xff1a;可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇&#xff08;数学建模清风主讲&#xff0c;适合零基础同学观看&#xff09;_哔哩哔哩_bilibili 在上一章中&#xff0c;我们学了许多文本处理的函数&#xff0c…

DS18B20与单片机的通信、DS18B20采集温度、MODBUS协议、练习框架

我要成为嵌入式高手之4月9日51单片机第四天&#xff01;&#xff01; ———————————————————————————— DS18B20温度传感器 单总线数字温度计 异步的半双工的串行通信 测量范围从-55℃ ~ 125℃&#xff0c;增量值为0.5℃ 要用DS18B20采集温度&am…

STM32之FreeRTOS移植

1.FreeRTOS的移植过程是将系统需要的文件和代码进行移植和裁剪&#xff0c;其移植的主要过程为&#xff1a; &#xff08;1&#xff09;官网上下载FreeRTOS源码&#xff1a;https://www.freertos.org/ &#xff08;2&#xff09;移植文件夹&#xff0c;在portable文件夹中只需…

【数字化转型】上市公司智能制造词频统计数据(1991-2022年)

数据来源&#xff1a;上市公司年报 时间跨度&#xff1a;1991-2022年 数据范围&#xff1a;上市公司 数据指标&#xff1a; 版本一 智能制造 智能机器 智能生产 机器人 全自动 全机器 版本二 宏观政策 中国制造2025 工业4.0 互联网 范式特征 自动化 信息化 信息…

多态【C/C++复习版】

目录 一、多态是什么&#xff1f;如何实现&#xff1f; 二、 什么是重写&#xff1f;有什么特点&#xff1f; 三、什么是协变&#xff1f; 四、析构函数能实现多态吗&#xff1f;为什么要实现&#xff1f; 五、override和final的作用是什么&#xff1f; 六、 多态的原理是…

【vscode】在本地加载远端环境并开发

【vscode】在本地利用远程服务器显卡跑代码 写在最前面vscode&#xff1a;远程到本地1、安装ssh插件2、添加服务器连接配置3、连接服务器4. SSH配置5. 在ssh中安装python解释器 vscode基本操作 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字篆刻时光…

得物 Zookeeper SLA 也可以 99.99% | 得物技术

一、背景 ZooKeeper&#xff08;ZK&#xff09;是一个诞生于2007年的分布式应用程序协调服务。尽管出于一些特殊的历史原因&#xff0c;许多业务场景仍然不得不依赖它。比如&#xff0c;Kafka、任务调度等。特别是在 Flink 混合部署 ETCD 解耦 时&#xff0c;业务方曾要求绝对…

双数据库的安装

双MySQL的安装 【0】前言 ​ 本地已经安装过mysql5.1版本&#xff0c;应项目需求需要安装mysql5.7版本&#xff1b; ​ 官方网站下载对应版本&#xff1a;https://downloads.mysql.com/archives/community/ 【1】压缩包下载完成后解压至本地磁盘 【2】进入根目录下bin文件夹…

Element-UI 自定义-下拉框选择年份

1.实现效果 场景表达&#xff1a; 默认展示当年的年份&#xff0c;默认展示前7年的年份 2.实现思路 创建一个新的Vue组件。 使用<select>元素和v-for指令来渲染年份下拉列表。 使用v-model来绑定选中的年份值。 3.实现代码展示 <template><div><el-…