leetcode 力扣刷题 数组交集(数组、set、map都可实现哈希表)

news2024/11/17 15:56:43

数组交集

  • 349. 两个数组的交集
    • 排序+双指针
    • 数组实现哈希表
    • unordered_set
    • unordered_map
  • 350. 两个数组的交集Ⅱ
    • 排序 + 双指针
    • 数组实现哈希表
    • unordered_map

349. 两个数组的交集

题目链接:349. 两个数组的交集
题目内容如下,理解题意:①交集中每个元素是唯一的,只能出现一次,所以本题要找的是同时出现在数组nums1和nums2中的元素,但是并不关心他们出现的次数;②输出结果的顺序不用考虑,也就是只要找到了同时出现在nums1和nums2中的元素就行,可以给数组排序(打乱了原本的顺序)再去查找、可以用map、set(其中key是无序的)……
在这里插入图片描述
这个题目暴力求解是可以的,暴力求解两层循环,将nums1和nums2的元素逐个对比,时间复杂度是O(m*n),因为nums1和nums2的长度都<=1000,所以最终也是能够运行的。
考虑更优的解法,直接一遍遍历nums1和nums2就好了。以下详述各解法:

排序+双指针

解法Ⅰ,对nums1和nums2排序后,从头开始遍历两个数组(下标用index1和index2),并将nums1[index1] = nums2[index2]的元素加入结果数组中。
存在的问题是:因为nums1和nums2中存在重复元素,如果找到了nums1[index1] = nums2[index2],且在nums1中,nums1[index1] 有重复,即nums1[index1+1] = nums1[index1] ,且在nums2中,nums2[index2]有重复,即nums2[index2+1] = nums2[index2]。那么直接对index++和index2++,会向结果数组中添加重复的元素。
解决:找到nums1[index1] = nums2[index2]后,index1++直到找到与之不同的下一个元素(就是跳过中间的相同的元素);index2++同样。
在这里插入图片描述

代码实现(C++):

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        vector<int> ans;
        sort(nums1.begin(),nums1.end());//先给nums1和nums2都排序
        sort(nums2.begin(),nums2.end());
        //排序后双指针(index1和index2遍历nums1和nums2
        for(int index1 = 0, index2 = 0; index1 < nums1.size() && index2 < nums2.size();){
            if(nums1[index1] == nums2[index2]){
                ans.emplace_back(nums1[index1]);    //如果找到在两个数组中出现的元素,加入到结果数组中
                //之后直接跳过和当前元素相同的一截,避免有可能向ans中重复添加该元素的可能
                do{
                    index1++;
                }while(index1 < nums1.size() && nums1[index1] == nums1[index1 - 1]);
                do{
                    index2++;
                }while(index2 < nums2.size() && nums2[index2] == nums2[index2 - 1]);
            }
            //如果不相等,更小的那个数向后移,同样是跳过和当前元素相同的一截,避免重复的比较
            else  if( nums1[index1] < nums2[index2]){
                do{
                    index1++;
                }while(index1 < nums1.size() && nums1[index1] == nums1[index1 - 1]);                
            }
            else{
                do{
                    index2++;
                }while(index2 < nums2.size() && nums2[index2] == nums2[index2 -1]);                
            }
        }
        return ans;
    }
};

数组实现哈希表

哈希表的好处体现在,它能够快速查找一个元素是否存在,时间复杂度是O(1)。我们要找nums1和nums2中同时存在的元素,换句话——查找nums1中某个元素是否出现在了nums2中。那么就可以用哈希表。因为题目中,nums1和num2的长度以及其中的int元素的大小都给了限制(<=1000),那么可以用数组来实现哈希表。
直接定义长度为1001的int数组count_1和count_2,统计nums1中元素的次数和nums2中元素出现的次数,最后对比count_1和count_2的每位元素,如果同时不为0的话,将对应元素加入到ans中。
代码如下(C++):

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        int count_1[1001] = {0}, count_2[1001] = {0};
        vector<int> ans;
        //分别统计nums1和nums2中元素出现情况
        for ( auto& num : nums1){
            count_1[num]=1;
        }
        for ( auto& num : nums2){            
            count_2[num]++;
        }
        for ( int i = 0; i <= 1000; i++){
        	//在两个数组中出现次数均>=1时,加入ans中
            if( count_1[i] && count_2[i])
                ans.emplace_back(i);
        }
        return ans;
    }
};

优化:上面需要用到两个数组count_1和count_2来分别统计nums1、nums2中元素出现的情况,之后还要遍历这俩数组。是否有可能只使用一个count数组,用两次?——遍历nums1的时候,出现的元素不统计次数,而是count[nums[i]]=1,标记该元素出现过;遍历nums2的时候,如果count[nums2[j]] !=0就表示在两个数组中同时存在;防止重复添加,再将count[nums2[j]]=0;
代码实现(C++):

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        int count[1001] = {0};
        vector<int> ans;
        //统计nums1中元素的出现情况
        for ( auto& num : nums1){
            count[num]=1;
        }
        //遍历nums2
        for ( auto& num : nums2){
            if(count[num]){ //同时判断nums2中的元素在nums1中是否出现
                count[num]=0;
                ans.emplace_back(num);
            }
        }      
        return ans;
    }
};

unordered_set

题意是要找交集,那么直接把数组变成集合,然后求两个集合交集就好。实现上,将vector变成unordered_set,然后对比两个unordered_set的key,找到重叠部分。
代码实现(C++):

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    	//把vector转化成unordered_set
        unordered_set<int> num_set1(nums1.begin(),nums1.end());
        unordered_set<int> num_set2(nums2.begin(),nums2.end());
        vector<int> ans;
        //遍历两个set,找交集;遍历size小的
        if( num_set1.size() < num_set2.size()){
            for( auto& key : num_set1)
                if(num_set2.count(key))
                    ans.emplace_back(key);
        }
        else{
            for( auto& key :num_set2)
                if(num_set1.count(key))
                    ans.emplace_back(key);
        }
        return ans;
    }
};

unordered_map

最后也能用map来实现,遍历nums1和nums2的同时,统计其中元素出现的次数,用unordered_map来存,key是数组中出现的元素,value是元素出现的次数; 之后找到两个map中重合的key。
代码(C++):

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int> count_1, count_2; 
        vector<int> ans;
        //用map统计数组中出现的元素及其次数
        for ( auto& num : nums1){
            count_1[num]++;
        }
        for ( auto& num : nums2){
            count_2[num]++;
        }
        if(count_1.size() < count_2.size()){
            for ( auto key_value : count_1)
                if(count_2.count(key_value.first))
                    ans.emplace_back(key_value.first);
        }
        else{
            for ( auto key_value : count_2)
                if(count_1.count(key_value.first))
                    ans.emplace_back(key_value.first);
        }
        return ans;
    }
};

350. 两个数组的交集Ⅱ

题目链接:350. 两个数组的交集Ⅱ
题目内容:在这里插入图片描述
这道题和上一题唯一不同的点在于:在nums1和nums2中同时出现的元素,如果出现次数不止一次,都需要加入到结果中。即不仅要统计同时出现在nums1和nums2中的元素,还要统计他们各自出现的次数(C1和C2),并在结果数组ans中重复min (C1, C2) 次。以下代码均在上一题基础上做一点改动即可。

排序 + 双指针

排序后数组元素逐个对比就好:双指针index1和index2,每次对比nums1[index1]和nums2[index2]的关系后,直接index1++,index2++:


class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        vector<int> ans;
        sort(nums1.begin(),nums1.end());
        sort(nums2.begin(),nums2.end());
        for(int index1 = 0, index2 = 0; index1 < nums1.size() && index2 < nums2.size();){
            if(nums1[index1] == nums2[index2]){
                ans.emplace_back(nums1[index1]);
                //下标直接向后移动,这样同时重复出现在两个数组中的元素能够重复添加
                index1++;
                index2++;               
            }
            else  if( nums1[index1] < nums2[index2]){
                index1++;              
            }
            else{
                index2++;               
            }
        }
        return ans;
    }
};

数组实现哈希表

先用数组count统计nums1中出现的元素,及其次数;再遍历nums2,同时出现在nums1中的元素,count[nums2[i]]- -,向结果数组ans中添加一次该元素。

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        int count[1001] = {0};
        vector<int> ans;
        //统计出现的元素,以及次数
        for ( auto& num : nums1){
            count[num]++;
        }
        for ( auto& num : nums2){
            if(count[num]){
            	//对于同时出现的元素,对其次数--,保证后续再出现该元素时,还能重复添加
                count[num]--;
                ans.emplace_back(num);
            }          
        }      
        return ans;
    }
};

unordered_map

只是将上面的数组换成了unordered_map。用数组实现哈希表适用于nums1和nums2都不大的,并且其中元素也不大的情况,当数组很大并且数组元素为int,大小没有限制的时候,用map更合适(或者set)
代码如下:

class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int> count;
        vector<int> ans;
        for(auto& num : nums1){
            count[num]++;
        }
        for(auto& num : nums2){
            if(count.count(num)){
                ans.emplace_back(num);
                count[num]--;
                //如果已经重复添加了min(c1,c2)次了,即便后续再出现也不能再添加了
                if(count[num]==0)
                    count.erase(num);
            }
        }
        return ans;
    }
};

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

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

相关文章

C++之std::pair<uint64_t, size_t>应用实例(一百七十七)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

零售行业供应链管理核心KPI指标(三)

完美订单满足率和退货率 完美订单满足率有三个方面的因素影响&#xff1a;订单按时、足量、无损交货。通常情况下零售企业追求线上订单履行周期慢慢达到行业平均水平&#xff0c;就是交付的速度变快了&#xff0c;这个肯定是一件好事情&#xff0c;趋势越来越好。 同时&#…

前端图片转base64,并使用canvas对图片进行压缩

目录 1.图片转base64的应用场景 2.图片转base64代码 3.对上传的图片进行压缩 1.图片转base64的应用场景 图片转base64通常用在用户上传图片的情况下使用&#xff0c;他的作用就是让用户看到预览的图片不受网络的影响。 这是传统的文件传输的流程&#xff1a;首先是用户选择…

浅析基于视频汇聚与AI智能分析的新零售方案设计

一、行业背景 近年来&#xff0c;随着新零售概念的提出&#xff0c;国内外各大企业纷纷布局智慧零售领域。从无人便利店、智能售货机&#xff0c;到线上线下融合的电商平台&#xff0c;再到通过大数据分析实现精准推送的个性化营销&#xff0c;智慧零售的触角已经深入各个零售…

牛客网华为OD前端岗位,面试题库练习记录02

题目一 删除字符串中出现次数最少的字符(HJ23) JavaScript Node ACM 模式 const rl require("readline").createInterface({ input: process.stdin }); var iter rl[Symbol.asyncIterator](); const readline async () > (await iter.next()).value;void (asyn…

【JavaEE基础学习打卡04】JDBC之MySQL数据库安装

目录 前言一、JDBC与数据库二、MySQL数据库1.MySQL数据库2.MySQL服务下载安装3.MySQL服务启动停止4.MySQL命令 三、MySQL客户端安装总结 前言 &#x1f4dc; 本系列教程适用于JavaWeb初学者、爱好者&#xff0c;小白白。我们的天赋并不高&#xff0c;可贵在努力&#xff0c;坚持…

Markdown编辑器 Mac版Typora功能介绍

Typora mac是一款跨平台的Markdown编辑器&#xff0c;支持Windows、MacOS和Linux操作系统。它具有实时预览功能&#xff0c;能够自动将Markdown文本转换为漂亮的排版效果&#xff0c;让用户专注于写作内容而不必关心格式调整。 Typora Mac版除了支持常见的Markdown语法外&#…

数据库连接池(c3p0和德鲁伊)

目录 连接池介绍 c3p0连接池 传统方法引入jar包 配置文件 德鲁伊连接池 德鲁伊工具类 传统jdbc数据库使用DriverManger来获取&#xff0c;每次向数据库建立连接需要将Connection加载到内存中&#xff0c;频繁的操作会造成占用很多系统资源&#xff0c;造成服务器崩溃&…

【计算机网络】13、ARP 包:广播自己的 mac 地址和 ip

机器启动时&#xff0c;会向外广播自己的 mac 地址和 ip 地址&#xff0c;这个即称为 arp 协议。范围是未经过路由器的部分&#xff0c;如下图的蓝色部分&#xff0c;范围内的设备都会在本地记录 mac 和 ip 的绑定信息&#xff0c;若有重复则覆盖更新&#xff08;例如先收到 ma…

python编程等级证书,python程序员证书

大家好&#xff0c;本文将围绕python编程等级证书展开说明&#xff0c;python证书含金量是一个很多人都想弄明白的事情&#xff0c;想搞清楚python程序员证书需要先了解以下几个事情。 全文共4231字&#xff0c;预计学习时长10分钟 图源&#xff1a;unsplash 在数据科学职业生涯…

工程项目管理系统源码+功能清单+项目模块+spring cloud +spring boot em

​ 工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#…

创建KVM虚拟机

文章目录 安装KVM虚拟机环境准备硬件虚拟化添加一块磁盘分区并格式化创建挂载目录并挂载分区上传镜像&#xff1a; virt-manager图形化安装下载virt-manager开始安装 virsh-install命令行安装安装组件使用virt-install安装 virsh管理虚拟机基本命令拓展命令 安装KVM虚拟机 环境…

JavaWeb-Listener监听器

目录 监听器Listener 1.功能 2.监听器分类 3.监听器的配置 4.ServletContext监听 5.HttpSession监听 6.ServletRequest监听 监听器Listener 1.功能 用于监听域对象ServletContext、HttpSession和ServletRequest的创建&#xff0c;与销毁事件监听一个对象的事件&#x…

jenkins gitlab 安装

目录 一 准备安装环境 二 安装gitlab软件 三 配置gitlab 四 重新加载配置启动gitlab 五 修改密码 五 创建用户组 一 准备安装环境 sudo yum update sudo yum install -y curl policycoreutils-python openssh-server安装 Postfix 邮件服务器&#xff0c;以便 Git…

OpenCV importerror:dll load failed

从预编译的二进制文件安装OpenCV&#xff0c;从github下载opencv-4.8.0-windows.exe 编译好的文件。按照官方文档拖入cv2.pyd文件。 https://docs.opencv.org/4.8.0/d5/de5/tutorial_py_setup_in_windows.html 使用pycharm运行时&#xff0c;出现报错&#xff0c;importerror…

机器学习基础之《分类算法(2)—K-近邻算法》

一、K-近邻算法(KNN) 1、定义 KNN K&#xff1a;就是一个自然数 N&#xff1a;nearest&#xff0c;最近的 N&#xff1a;neighbourhood&#xff0c;邻居 如果一个样本在特征空间中的k个最相似(即特征空间中最邻近)的样本中的大多数属于某一个类别&#xff0c;则该样本也属于这…

CS5263替代停产IT6561连接DP转HDMI音视频转换器ASL 集睿致远CS5263设计电路原理图

ASL集睿致远CS5263是一款DP1.4到HDMI2.0b转换器芯片&#xff0c;设计用于将DP1.4源连接到HDMI2.0b接收器。 CS5263功能特性&#xff1a; DP接口包括4条主通道、辅助通道和HPD信号。接收器支持每通道5.4Gbps&#xff08;HBR2&#xff09;数据速率。DP接收机结合了HDCP1.4和HDCP…

SharkTeam:Worldcoin运营数据及业务安全分析

Worldcoin的白皮书中声明&#xff0c;Worldcoin旨在构建一个连接全球人类的新型数字经济系统&#xff0c;由OpenAI创始人Sam Altman于2020年发起。通过区块链技术在Web3世界中实现更加公平、开放和包容的经济体系&#xff0c;并将所有权赋予每个人。并且希望让全世界每一个人都…

tauri-vue:快速开发跨平台软件的架子,支持自定义头部UI拖拽移动和窗口阴影效果

Tauri Vue Typescript 一个使用 taurivuets 开发跨平台软件的模板&#xff0c;支持窗口头部自定义 UI 和拖拽和窗口阴影&#xff0c;不用再自己做适配了&#xff0c;拿来即用&#xff0c;非常 nice。而且已经封装好了 tauri 的 http 请求工具&#xff0c;省去很多弯路。开源…

【HCIP】BGP总结

一、bgp介绍 1.概念 边界网关协议BGP&#xff08;Border Gateway Protocol&#xff09;是一种实现自治系统AS之间的路由可达&#xff0c;并选择最佳路由的路径矢量路由协议。目前在IPV4环境下主要使用BGPV4&#xff0c;目前市场上也存BGPV4&#xff0c;BGPV4在BGPV4的基础上支…