【代码随想录】二刷-哈希表

news2024/11/30 2:42:24

哈希表

  • 《代码随想录》
  • 哈希表一般用来快速查找某个元素是否在一个集合中。
  • 如果使用枚举的话时间复杂度为O(n),而使用哈希表只O(1)就可以做到。——元素查询。

242.有效的字母异位词

  • 使用unordered_map
// 时间复杂度 O(n)
// 空间复杂度 O(n)
class Solution {
public:
    bool isAnagram(string s, string t) {
        unordered_map<char,int>mp;
        for(char& c:s)mp[c]++;
        for(char& c:t)mp[c]--;
        for(auto m:mp){
            if(m.second != 0)return false;
        }
        return true;
    }
};
  • 使用数组
// 时间复杂度 O(n)
// 空间复杂度 O(1)-因为空间上定义的是一个常量大小的辅助数组
class Solution {
public:
    bool isAnagram(string s, string t) {
        int record[26] = {0};
        for(char& c:s)record[c-'a']++;
        for(char& c:t)record[c-'a']--;
        for(int i = 0 ;i < 26;i++){
            if(record[i] != 0)return false;
        }
        return true;
    }
};

349. 两个数组的交集

  • unordered_set底层实现同样是哈希表,使用它可以完成去重操作。
    • 因为其中的每一个元素都是唯一的。
// 时间复杂度O(n)
// 空间复杂度O(n)
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int>nums1_count;
        unordered_set<int>ret;
        for(int& c:nums1)nums1_count.emplace(c);
        for(int& c:nums2){
            if(nums1_count.find(c) != nums1_count.end())ret.emplace(c);
        }
        return vector<int>(ret.begin(),ret.end());
    }
};
  • 本体限制了用例大小,所以我们同样可以使用数组来进行哈希映射。
  • 如果哈希值比较少、特别分散、跨度特别大,使用数组就造成空间的极大浪费。
// 时间复杂度 O(n)
// 空间复杂度 O(n)
class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        unordered_set<int>ret;
        int count[1000] = {0};
        for(int &c:nums1){
            count[c] = 1;
        }
        for(int &c:nums2){
            if(count[c] == 1){
                ret.emplace(c);
            }
        }
        return vector<int>(ret.begin(),ret.end());
    }
};

350.两个数组的交集 II

  • 使用两个哈希分别保存nums1和nums2中的元素及元素个数。
  • 然后选择一种一个哈希表进行遍历,看另外一个哈希表中是否有相同元素,统一元素选择出现较少的次数,然后push进结果数组ret中。
// 时间复杂度 O(n)
// 空间复杂度 O(n)
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int>mp1,mp2;
        vector<int>ret;
        for(int& c:nums1)mp1[c]++;
        for(int& c:nums2)mp2[c]++;
        
        for(auto k:mp1){
            if(k.second != 0 && mp2[k.first]){
                int count = min(k.second,mp2[k.first]);
                for(int i = 0;i < count;i++){
                    ret.emplace_back(k.first); 
                }
            }
        }
        return ret;
    }
};
  • 使用一个哈希表来存储nums1的元素个数,然后开始遍历nums2,如果哈希表中该元素数量大于1,则–,push到ret中。
// 时间复杂度 O(n)
// 空间复杂度 O(n)
class Solution {
public:
    vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
        unordered_map<int,int>mp;
        vector<int>ret;
        for(int& c:nums1){
            mp[c]++;
        }
        for(int& c:nums2){
            if(mp[c] > 0){
                ret.emplace_back(c);
                mp[c]--;
            }
        }
        return ret;
    }
};

第202题. 快乐数

  • 题目中说了可能会死循环,所以出现已经出现过的数了,直接return false
  • 用一个哈希表来保存出现过的数。
// 时间复杂度 O(logn)
// 空间复杂度 O(logn)
class Solution {
public:
    int getSum(int n){
        int sum = 0;
        while(n){
            int tmp = n%10;
            sum += tmp*tmp;
            n /= 10;
        }
        return sum;
    }
    bool isHappy(int n) {
        unordered_set<int>st;
        while(1){
            int tmp =getSum(n);
            if(tmp == 1){
                return true;
            }else{
                if(st.find(tmp) != st.end()){// 找到了——出现过
                    return false;
                }else{// 没找到
                    st.emplace(tmp);
                }
            }
            n = tmp;// 更新
        }
    }
};

1. 两数之和

  • “数组中同一个元素在答案里不能重复出现。”,看到这句话,就知道要使用哈希表啦。
// 时间复杂度 O(n)
// 空间复杂度 O(n)
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 注意: 题目说,只会存在一个有效答案。
        unordered_map<int,int>map;
        int n = nums.size();
        for(int i = 0;i < n;i++){
            auto iter = map.find(target-nums[i]);
            if(iter != map.end()){// 找到了
                return {iter->second,i};
            }else{// 没有找到
                map[nums[i]] = i;
            }
        }
        return {};
    }
};

454. 四数相加 II

  • 遍历num1,num2,使用一个哈希表来存储二者元素和出现的可能及对应的次数。
  • 遍历num3,num4,使用-减去其中的元素组合和,得到一个差值,并在哈希表中查询是否有这个差值,存在,将其数量累加到结果上。
// 时间复杂度 O(n²)
// 空间复杂度 O(n)
class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int,int>mp;
        int ret = 0;
        for(int& a:nums1){
            for(int& b:nums2){
                mp[a+b]++;
            }
        }
        for(int& c:nums3){
            for(int& d:nums4){
                if(mp.find(0-c-d) != mp.end()){
                    ret += mp[0-c-d];
                }
            }
        }
        return ret;
    }
};

383. 赎金信

  • 不是所有时候都使用哈希表的,有时候使用数组可能会获得更高的效率。
  • 例如本题中,我们可以得到字符出现的范围,26个字母,可卡开辟出数组的大小。
  • 在本体情况下,使用map的空间消耗要比数组大一些,因为map要维护红黑树或者哈希表,而且还要做哈希函数,会更费时。
// 时间复杂度 O(n)
// 空间复杂度 O(1)-常量辅助数组
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26] = {0};
        for(char &c:magazine){// 使用magazine去组成ransomNote所以先遍历它
            record[c-'a']++;
        }
        for(char& c:ransomNote){
            if(record[c-'a'] > 0){
                record[c-'a']--;
            }else{
                return false;
            }
        }
        return true;
    }
};
  • 暴力
// 时间复杂度O(n²)
// 空间复杂度O(1)
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int nr = ransomNote.size();
        int mr = magazine.size();
        for(int i = 0;i< mr;i++){
            for(int j = 0;j <nr;j++){
                if(magazine[i] == ransomNote[j]){//找到了一个字符
                    ransomNote.erase(ransomNote.begin()+j);
                    break;//找到了一个字符
                }
            }
        }
        return ransomNote.size() == 0;
    }
};

15. 三数之和

  • 哈希表法,
  • 补充: 详见下图,主要为b去重理解。
    • 即,去除同一个元素出现3次以上引起的重复和用于优化剪枝。

在这里插入图片描述

// 时间复杂度 O(n²)
// 空间复杂度 O(n)
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>>ret;
        int n = nums.size();
        sort(nums.begin(),nums.end());// 排序是为了方便去重
        // a = nums[i] 
        // b = nums[j]
        // c = 0-a-b
        for(int i = 0; i < n;i++){// a
            if(nums[i] > 0){// 排完序了,第一个a还是正数,无法求和==0
                break;
            }
            if(i > 0 && nums[i] == nums[i-1]){// a去重
                continue;
            }
            unordered_set<int>set;
            for(int j = i + 1;j < n;j++){// b
                if(j > i+2 &&
                    nums[j] == nums[j-1] &&
                    nums[j-1] == nums[j-2]){// b去重
                        continue;
                }
                int c = 0-nums[i]-nums[j];// c
                if(set.find(c) != set.end()){// 找到了
                    ret.push_back({nums[i],nums[j],c});
                    set.erase(c);// c去重
                }else{// 没找到,将当前元素b放入
                    set.insert(nums[j]);
                }
            }
            
        }
        return ret;
    }
};
  • 双指针:
    • 本题目中使哈希法并不合适,因为在去重的操作中有许多细节需要注意。
    • 相对于哈希法,本题使用双指针法会更高效些。
  • 注意:
    • 题目中的不能重复,指的是一个组合不能重复,而组合内的三个元素是可以有重复的。
    • 在遍历第一个元素时候,去重的判断,就应该为nums[i] == nums[i-1]:
      • 若为nums[i] == nums[i+1],则为与组合内的元素对比。因为右边的第一个元素为left。
    • 其中一个较难点是对b,c去重的理解。详见代码中的注释。
// 时间复杂度 O(n²)
// 空间复杂度 O(n)
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>>ret;
        sort(nums.begin(),nums.end());
        int n = nums.size();
        for(int i = 0; i < n;i++){
            if(nums[i] > 0)break;// 剪枝
            if(i > 0 && nums[i] == nums[i-1]){// a去重
                continue;
            }
            int left = i+1;
            int right = n-1;
            while(right > left){
                int tmpSum = nums[i] + nums[left] + nums[right];
                if( tmpSum > 0)right--;
                else if(tmpSum < 0)left++;
                else{// 找到结果了
                    ret.push_back(vector<int>{nums[i],nums[left],nums[right]});
                    // b c去重,例如: 已知两个数的和为0,知道其中的一个数,另一个数就是确定的了,所以来两个要收缩。
                    // 当前数与下一个数进行判断是否相同
                    while(right > left && nums[right] == nums[right-1])right--;
                    while(right > left && nums[left] == nums[left+1])left++;
                    
                    // 上面两个循环最终停在上一个元素的最后一次(前/后)出现的位置
                    // 当我们确定一个a之后,b+c的和就确定了;
                    // 进一步说,如果b+c = 5,即b=1的时候,c只能为4,
                    // 所以b c如果与之前相同,都要跳过,即left++/right++(如上面两个while中所示)
                    // 所以左右边界同时收缩,即完成去重。
                    // 下面收缩后,left right 都为下一个与之前计算收集结果时不同的元素。
                    left++;
                    right--;
                }
            }
        }
        return ret;
    }
};

18. 四数之和

  • 双指针法
// 时间复杂度 O(n³)
// 空间复杂度 O(n)
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        vector<vector<int>>ret;
        int n =  nums.size();
        sort(nums.begin(),nums.end());
        for(int i = 0; i < n ; i++){
            if(nums[i] > target && 
                nums[i] > 0){// 剪枝
                break;
            }
            if(i > 0 && nums[i] == nums[i-1])continue;
            for(int j = i + 1; j < n;j++){
                // 注意这里判断nums[k]+nums[i] = 0,
                // 如果后面还有数,当前两个相加为0,大于target,说明target为负数,后面不可能再有答案,0 + 整数 > 0 
                if(nums[i]+nums[j] > target &&
                    nums[i]+nums[j] >= 0)continue;
                if(j > i + 1 && nums[j] == nums[j-1])continue;
                
                int left = j+1;
                int right = n-1;
                while(right > left){
                    // 相加有可能溢出用long存
                    long tmpSum = (long)nums[i]+nums[j]+nums[left]+nums[right];
                    if(tmpSum > target)right--;
                    else if(tmpSum < target)left++;
                    else{
                        ret.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});
                        while(left < right && nums[right] == nums[right-1])right--;
                        while(left < right && nums[left] == nums[left+1])left++;

                        left++;
                        right--;
                    }
                }
            }
        }
        return ret;
    }
};

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

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

相关文章

嵌入式分享合集94

一、单片机硬件电路设计 减少后级电源对前级的影响&#xff0c;防止电源正负接反烧坏后级电路&#xff0c;防止电源关电时电流倒灌&#xff0c;但经过二极管有0.4V左右压降&#xff0c;需要考虑经过0.4V降压后会不会低于后级电路的正常工作电压。 一、按键电路 R1上拉电阻&…

用C语言开发入门游戏FlappyBird

前言 《flappy bird》是一款由来自越南的独立游戏开发者Dong Nguyen所开发的作品&#xff0c;游戏于2013年5月24日上线&#xff0c;并在2014年2月突然暴红。2014年2月&#xff0c;《Flappy Bird》被开发者本人从苹果及谷歌应用商店撤下。2014年8月份正式回归APP Store&#xf…

java从零开始系统性学习完整笔记(一)

java从零开始系统性学习完整超全资源笔记(还在更新中&#xff09; 前言 资源来自&#xff1a;王汉远java基础&#xff0c; B站视频&#xff1a; https://www.bilibili.com/video/BV1b4411g7bj/?spm_id_from333.1007.top_right_bar_window_custom_collection.content.click&a…

渗透测试之分享常用工具、插件和脚本(干货)

BRUP插件&#xff1a; 漏洞挖掘插件&#xff1a;Autorize、CSRF Token Tracker、XSS Validator、Turbo Intruder 辅助插件&#xff1a;HaE、sqlmap4brup、hackbar、Software Vulnerability Scanner 浏览器插件&#xff1a; wappalyzer、MySSL、Cookie Editor 脚本&#xff1a; …

Vue学习:vue生命周期

Vue实例有一个完整的生命周期&#xff0c;也就是从开始创建、初始化数据、编译模板、挂载Dom、渲染→更新→渲染、卸载等一系列过程&#xff0c;我们称这是Vue的生命周期。通俗说就是Vue实例从创建到销毁的过程&#xff0c;就是生命周期。生命周期又称为生命周期回调函数&#…

水果叠叠乐

水果叠叠乐 介绍 消消乐是一款益智类小游戏&#xff0c;最近比较火爆的一种是立体叠叠乐式的&#xff0c;然后小蓝也想开发一个自己练练手&#xff0c;给它起名叫“水果叠叠乐”。 准备 本题已经内置了初始代码&#xff0c;打开实验环境&#xff0c;目录结构如下&#xff1…

OSPF高级配置——学习OSPF路由协议的高级应用

作者简介&#xff1a;一名在校云计算网络运维学生、每天分享网络运维的学习经验、和学习笔记。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.路由重分发及配置 1.路由重分发概述 2.理解路由重分发 3.路…

【HMS Core】华为分析SDK如何申请数据导出功能?

1、问题描述 项目中集成了华为分析SDK&#xff0c;现在有一个需求&#xff0c;想要申请数据导出功能&#xff0c;申请页面提示数据导出功能目前仅对部分邀请伙伴开放&#xff0c;需要通过在线提单的方式申请开通此功能&#xff0c;那么具体该如何操作呢&#xff1f; 2、解决方…

校园跑腿微信小程序,校园跑腿小程序,微信小程序跑腿系统毕设作品

项目背景和意义 目的&#xff1a;本课题主要目标是设计并能够实现一个基于微信校园跑腿小程序系统&#xff0c;前台用户使用小程序发布跑腿任何和接跑腿任务&#xff0c;后台管理使用基于PHPMySql的B/S架构&#xff1b;通过后台管理跑腿的用户、查看跑腿信息和对应订单。 意义…

C++ Reference: Standard C++ Library reference: C Library: cwchar: wcstoll

C官网参考链接&#xff1a;https://cplusplus.com/reference/cwchar/wcstoll/ 函数 <cwchar> wcstoll long long int strtoll (const wchar_t* str, wchar_t** endptr, int base); 将宽字符串转换为long long整数 解析C宽字符串str&#xff0c;将其内容解释为指定base的…

高级FPGA设计结构实现和优化_(六)静态时序分析

高级FPGA设计结构实现和优化_静态时序分析标准分析锁存器组合反馈标准分析 静态时序分析(STA)指的是在一个设计中与一组约束有关的所有时序路径的综合性分析&#xff0c;为了确定一个设计是否是“时序一致的”。由FPGA设计者遇到的基本路径是输入到触发器、触发器到触发器、触发…

MySQL进阶一 一条select语句的执行流程

文章目录前言MySQL的执行流程第一步&#xff1a;连接器第二步&#xff1a;查询缓存第三步&#xff1a;解析SQL第四步&#xff1a;执行 SQL预处理器优化器执行器主键索引查询全表扫描索引下推总结前言 有一位同志问我为什么很久没更新了&#xff0c;因为前一个礼拜在复盘JavaSE…

【详解】手撕 一维、二维、三维差分数组原理(附图解,模板,例题分析)

【差分专题】 引言 ​ 差分是一种处理数据巧妙而简单的方法&#xff0c;可以应用于区间修改和询问问题。例如&#xff0c;将给定的数据集合 A 分成很多区间&#xff0c;并对这些区间进行很多次操作&#xff0c;每次都是对某段区间内的所有元素做相同的加减操作&#xff0c;此…

YOLOv7学习笔记(一)——概述+环境+训练

一、环境安装测试 1、创建环境conda create -n yolo python3.7conda activate yolo2、安装pytorchconda install pytorch torchvision cudatoolkit11.3 -c pytorch11.3为cuda版本号3、克隆yolov5git clone https://github.com/WongKinYiu/yolov7 # clonecd yolov7pip install…

真的要转到云IDE了吗?VS Code的开源IDE

云IDE产品介绍 云IDE使用教程 免费使用地址&#xff1a;点击【云IDE】&#xff0c;即可开始创建工作空间啦~ 前言 CSDN最新产品【云IDE】来啦&#xff01;【云IDE】将为各位技术er一键秒级构建云开发环境&#xff0c;提升开发效率&#xff01; 1. 什么是IDE&#xff1f; 做…

PyTorch 1.13 正式发布:CUDA 升级、集成多个库、M1 芯片支持

内容导读&#xff1a;近日&#xff0c;PyTorch 团队在官方博客宣布 Pytorch 1.13 发布。本文将详细围绕新版本的 4 大亮点展开介绍。 据官方介绍&#xff0c;PyTorch 1.13 中包括了 BetterTransformer 的稳定版&#xff0c;且不再支持 CUDA 10.2 及 11.3&#xff0c;并完成了向…

大数据项目之电商数仓、业务数据介绍、业务数据模拟、生成业务数据、业务数据建模

文章目录6. 业务数据介绍6.5 业务数据模拟6.5.1 连接MySQL6.5.2 建表语句6.5.3 生成业务数据6.5.3.1 在hadoop102的/opt/module/目录下创建db_log文件夹6.5.3.2 把gmall2020-mock-db-2021-11-14.jar和application.properties上传到hadoop102的/opt/module/db_log路径上6.5.3.3 …

[CSS]常见布局技巧

前言 系列文章目录&#xff1a; [目录]HTML CSS JS 根据视频和PPT整理视频及对应资料&#xff1a;HTML CSS 老师笔记&#xff1a; https://gitee.com/xiaoqiang001/html_css_material.git视频&#xff1a;黑马程序员pink老师前端入门教程&#xff0c;零基础必看的h5(html5)css3…

榛子树搜索算法(Hazelnut tree search algorithm,HTS)附matlab代码

✅作者简介&#xff1a;热爱科研的Matlab仿真开发者&#xff0c;修心和技术同步精进&#xff0c;matlab项目合作可私信。 &#x1f34e;个人主页&#xff1a;Matlab科研工作室 &#x1f34a;个人信条&#xff1a;格物致知。 更多Matlab仿真内容点击&#x1f447; 智能优化算法 …

c++基础(十四)——继承

一、继承的基本语法 继承是面向对象三大特性之一&#xff0c;有些类与类之间存在特殊的关系&#xff0c;当定义这些类时&#xff0c;下级别的成员除了拥有上一级的共性&#xff0c;还有自己的特性。这个时候我们就可以考虑利用继承的技术&#xff0c;减少重复代码。 基本语法&…