【代码随想录】哈希

242. 有效的字母异位词

原题链接

算法思想:哈希,排序

哈希思想:重点就是迅速查找,通过key和值的迅速匹配,所以当题目是与 “唯一性” 有关时可用
用哈希表维护字母出现的次数

方法一:哈希

我的做法:用了map

class Solution {
public:bool isAnagram(string s, string t) {if(s.size()!=t.size())  //如果没有这句会"a","a,b"错误return false;map<char,int> a;for(int i=0;i<s.size();i++){a[s[i]]++;}for(int i=0;i<t.size();i++){if(a.count(t[i])==1){a[t[i]]--;}}for(int i=0;i<a.size();i++){if(a[i]!=0)return false;}return true;}
};

官方
使用的是数组来表示哈希,一个26个元素的数组,将每个字母-‘a’,对应到数组的位置下标。

class Solution {
public:bool isAnagram(string s, string t) {vector<int> a(26);for(int i=0;i<s.size();i++){a[s[i]-'a']++;}for(int i=0;i<t.size();i++){a[t[i]-'a']--;}for(int i=0;i<a.size();i++){if(a[i]!=0)return false;}return true;}
};

方法二:排序

题目等价于排序后看两个字符串是否相等.
sort对string排序: sort( str.begin(), str.end() );

class Solution {
public:bool isAnagram(string s, string t) {sort(s.begin(),s.end());sort(t.begin(),t.end());if(s==t)return true;return false;}
};

383. 赎金信

原题链接

这里用数组比用undered_map简单多了
数组直接天然顺序0-25 就是a-z,直接一对一比较,map还要找key再比较
结论:string类型查找时,只有小写字母,使用数组当哈希很方便!

注意:
该观点错误:【map不能重复插入,计算次数,每次还要判断是不是第一次插入】map遇到key值相同的字符时,可以直接mp[key]++, 计算次数。,而insert不会进行覆盖,每次需要判断是否已经存在,如果存在,则[key]++,不存在插入{key,0},见下方的引出问题:

引出问题:map出现相同key值时,会怎么处理?

当使用insert进行相同key值插入时,不会进行覆盖,原理:insert源码是先进行遍历了,如果出现相同key值,就直接返回,如果没有则插入;
当使用[ ],是重载的,所以可以进行相同key值的覆盖。

哈希数组:

 vector<int>r(26);vector<int>m(26);for(int i=0;i<magazine.size();i++){m[magazine[i]-'a']++;}for(int j=0;j<ransomNote.size();j++){r[ransomNote[j]-'a']++;}for(int i=0;i<26;i++){if(m[i]<r[i]){return false;}}return true;

哈希map:

class Solution {
public:bool canConstruct(string ransomNote, string magazine) {//方法一:先排序后遍历//方法二:magazine存储到哈希,遍历ransomNote,再在magazine中是否全可以查找得到//  if(magazine.size()<ransomNote.size())//     return false;//  sort(ransomNote.begin(),ransomNote.end());//  sort(magazine.begin(),magazine.end());//  for(int i=0;i<magazine.size();i++){//      if(magazine[i]==ransomNote[i])//           return false;//  }//  return true;unordered_map<char,int>mp;unordered_map<char,int>mp1;for(int i=0;i<magazine.size();i++){//key唯一mp[magazine[i]]++;}for(int i=0;i<ransomNote.size();i++){mp1[ransomNote[i]]++;}for(auto it: mp1){if(mp.count(it.first)==0)return false;if(it.second>mp[it.first]){return false;}}return true;//不是m中的个数只要>=0即可,不是不等于0,因为m包含r,m中的次数可能比r多,只要m次数>=r可以}
};

349. 两个数组的交集

原题目链接
算法思路:排序+双指针
我的做法:

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {sort(nums1.begin(),nums1.end());sort(nums2.begin(),nums2.end());int len1=nums1.size();int len2=nums2.size();vector<int> v;set<int> s;set<int>:: iterator it;//      int minlen=len1<len2?len1:len2;int p=0,q=0;while(p<len1&&q<len2){if(nums1[p]==nums2[q]){//  v.push_back(nums1[p++]);s.insert(nums1[p++]);q++;}else if(nums1[p]<nums2[q]){p++;}else{q++;}      }for(it=s.begin();it!=s.end();it++){v.push_back(*it);}return v;}
};

冗余点:
唯一性判断可以通过有序这个特性,不用再设置set,因为每次加入到vector里的元素也是有序的。

官方:
因为是有序的,通过比较插入vector元素的值和v.back()是否相等来确定插入元素的唯一性。注意当size()==0时,即没有元素,调用v.back()会报错!

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {sort(nums1.begin(), nums1.end());sort(nums2.begin(), nums2.end());int length1 = nums1.size(), length2 = nums2.size();int index1 = 0, index2 = 0;vector<int> intersection;while (index1 < length1 && index2 < length2) {int num1 = nums1[index1], num2 = nums2[index2];if (num1 == num2) {// 保证加入元素的唯一性if (!intersection.size() || num1 != intersection.back()) {intersection.push_back(num1);}index1++;index2++;} else if (num1 < num2) {index1++;} else {index2++;}}return intersection;}
};作者:LeetCode-Solution
链接:https://leetcode.cn/problems/intersection-of-two-arrays/solution/liang-ge-shu-zu-de-jiao-ji-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间复杂度:O(mlogm+nlogn)
其中 m 和 n分别是两个数组的长度。对两个数组排序的时间复杂度分别是 O(m log m)和 O(nlog n),双指针寻找交集元素的时间复杂度是 O(m+n),因此总时间复杂度是O(mlogm+nlogn)。
空间复杂度:O(log m+log n)
其中 m 和 n 分别是两个数组的长度。空间复杂度主要取决于排序使用的额外空间。

随想录:
使用unordered_set

class Solution {
public:vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {unordered_set<int> result_set; // 存放结果unordered_set<int> nums_set(nums1.begin(), nums1.end());for (int num : nums2) {// 发现nums2的元素 在nums_set里又出现过if (nums_set.find(num) != nums_set.end()) {result_set.insert(num);}}return vector<int>(result_set.begin(), result_set.end());}
};

注意:
但是要注意,使用数组来做哈希的题目,是因为题目都限制了数值的大小。而这道题目没有限制数值的大小,就无法使用数组来做哈希表了。
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。

202. 快乐数

原题链接
算法思路: 重点是找到循环出口!!看清楚快乐数和不是快乐数的返回条件是什么!
快乐数:最后结果为1
不快乐数:无限循环且值不可能为1
所以查找是否重复出现使用哈希,undered_set

class Solution {
public:bool isHappy(int n) {unordered_set<int> s;int sum=0;while(1){sum+=pow(n%10,2);n=n/10;if(n==0) //如果没有n==0,sum还没计算完,即计算到中间某一步,就开始查找了{ if(sum==1)return true;if(s.count(sum)==0)                  {s.insert(sum);    n=sum;sum=0;   } else return false;}}}};

bug点

  1. 求一个数各个位的值,语句顺序影响结果!

1. 两数之和

原题链接
思路:暴力,哈希
哈希:
哈希可以用于查找是否出现,通过等式a+b=target来查找,此时,b=target-a;
使用unordered_set

class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {map<int,int> mp;// for(int i=0;i<nums.size();i++)// {//     mp[nums[i]]=i;// }for(int i=0;i<nums.size();i++){auto it=mp.find(target-nums[i]);if(it!=mp.end()){return {it->second,i};}mp[nums[i]]=i;}return {};}
};

bug点:

  1. 之前的思路先将数组存储到undered_set里,再遍历,在哈希表中查找,看是否出现了target-nums[i],这个时候,有两个错误点,一是map第一次遍历存储时,只能插入不相同的元素,如[3,3], map只能插入一个3;二是插入进去后,下一次找target-a时,如果是6-3=3这种,就会返回自己的坐标,如【3,2,4】 6
  2. 记住函数最后一定要返回值,否则报错
    随想录
    用的unordered_map

其他试错:
不能用双指针,首先,要返回的是原来的坐标,如果先排序再用两数之和,那么返回的left和right就是排序后的坐标。
如果不排序来求那么不能保证可以遍历到所有情况。
错误的双指针如下:

class Solution {
public:vector<int> twoSum(vector<int>& nums, int target) {int left=0,n=nums.size();int right=n-1;sort(nums.begin(),nums.end());while(left<=right){int sum=nums[left]+nums[right];if(sum==target){return {left,right};}else if(sum>target)right--;else left++;}return {0,0};  //记住必须要有返回值}
};

454. 四数相加 II

原题链接

算法思路:
由等式a+b=-(c+d),因为题目只要返回个数,所以就不用记录下标。将a+b的和存储起来,再遍历第三,四个数组看三+四的相反数是否存在和的数组中。
本来想着使用unordered_set, 但是可能和会重复,所以使用unordered_map,key为和,值为出现该和的次数。
遍历后两个数组时,就将sum加起来。

我的代码:

class Solution {
public:int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {unordered_map<int,int>mp;int sum=0;for(int i=0;i<nums1.size();i++){for(int j=0;j<nums2.size();j++){   // mp.insert(pair<int,int>(nums1[i]+nums2[j]));mp[nums1[i]+nums2[j]]++;}}for(int i=0;i<nums1.size();i++)for(int j=0;j<nums1.size();j++){if(mp.count(-(nums3[i]+nums4[j])))sum+=mp[-(nums3[i]+nums4[j])];}return sum;}
};

15 . 三数之和

原题链接

本题目用哈希麻烦

方法一:排序+双指针
二三重循环可以并行!所以出现了双指针
当我们需要枚举数组中的两个元素时,如果我们发现随着第一个元素的递增,第二个元素是递减的,那么就可以使用双指针的方法,将枚举的时间复杂度从 O(N^2)减少至 O(N),如本题和为固定值0,a,和值不变,b增大,c减小

本题目思路:
使用排序+双指针的大框架,加一些剪枝操作,如第一个数字如果是大于0 的,那么后面不可能三数之和为0,直接return 。
难点是去重操作,要答案不同,所以每当遍历到一个新的数字,都必须与前一个比较,看是否相同,三个数字都要去重。最容易出现bug的是出现死循环,当等于题目条件时,必须left,right都移动。

class Solution {
public:vector<vector<int>> threeSum(vector<int>& nums) {//与两数之和不同的是,两数之和的和是固定的target,本题目的c是不固定的,在数组里内//由此,可以想到,遍历该数组,每次都固定和不变,剩下的两个用双指针,找到后加入vector,这一点与两数之和的不同,因为不用输出下标,所以可以用双指针int n=nums.size();unordered_set<int> s;vector<vector<int>>v;int sum=0;sort(nums.begin(),nums.end());for(int i=0;i<nums.size();i++){if(nums[i]>0)  //这里直接return ,否则不通过 1 1 -2 return v;if(i>0&&nums[i]==nums[i-1])continue;int left=i+1,right=n-1;while(left<right){if(nums[left]+nums[right]+nums[i]<0){//去重left++;  }else if(nums[left]+nums[right]+nums[i]>0){right--;              }else{v.push_back({nums[i],nums[left],nums[right]});//继续在里面寻找,否则找到一次后会死循环left++;right--;while(left<right&&nums[left]==nums[left-1])left++; while(left<right&&nums[right]==nums[right+1])//right是和后一个比较,因为后一个是已经判断过的right--;}}}return v;}
};

bug点

  1. while(left<right && …) 记住只要出现left++,right–,就要判断一下left<right
  2. 相等时内缩 left,right, 否则死循环
  3. 去重操作!right是与right+1作比较
  4. if(i>0&&nums[i]==nums[i-1]) 当与前一个对比时,避免越界,可以限制短路条件i>0

18. 四数之和

原题目链接
与三数之和解法相似,只不过剪枝操作不同,注意这里target可能为负数,所以不要nums[i]>target这个剪枝操作。
官方答案还增加了一个<target,直接一下子判断四个,则continue本层循环

class Solution {
public:vector<vector<int>> fourSum(vector<int>& nums, int target) {int n=nums.size();sort(nums.begin(),nums.end());vector<vector<int>> v;int left,right;for(int i=0;i<n;i++){// if(nums[i]>target)  //      return v;  如果target小于0那也不行      if(i>0&&nums[i]==nums[i-1])continue;for(int j=i+1;j<n;j++){// if(nums[j]>target)//      return v;  不应该,若第一个为负数,则两者相加可能是小于target的if(j>i+1&&nums[j]==nums[j-1])continue;int sum=nums[i]+nums[j];left=j+1;right=n-1;// if(sum>target)//    return v;  [-3,-2,-1,0,0,1,2,3]  0 少了[-1,0,0,1]while(left<right){if((long)sum+nums[left]+nums[right]>target){right--;}else if((long)sum+nums[left]+nums[right]<target){left++;}else{v.push_back({nums[i],nums[j],nums[left],nums[right]});left++;right--;while(left<right&&nums[left]==nums[left-1])left++;while(left<right&&nums[right]==nums[right+1])right--;}}}}return v;}
};

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

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

相关文章

Spring Cloud Alibaba、Spring Cloud 与 Spring Boot各版本的对应关系

参考spring-cloud-alibaba github wiki说明&#xff1a;版本说明 下面截取说明&#xff1a; 2022.x 分支 2021.x 分支 2.2.x 分支 组件版本关系

ChatGPT Search VS Kimi探索版:AI搜索哪家强?!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

Linux常用命令,持续更新钟

在Linux系统中&#xff0c;你可以使用多种命令来拷贝和移动文件及目录。以下是常用的几个命令及其用法&#xff1a; 一、拷贝文件或目录 cp 命令 cp 命令用于拷贝文件或目录。 拷贝文件&#xff1a; cp source_file destination_file 例如&#xff1a; cp file1.txt /hom…

基于SpringBoot的校园二手商品在线交易系统+含项目运行说明文档

一、项目技术栈 二、项目功能概述 管理员可以完成的功能包括管理员登录、管理员首页展示、系统设置、物品管理、学生管理、评论管理、举报管理、新闻公告、网站设置等&#xff0c;前台的客户可以进行查看所有商品分类、搜索商品、登录或注册、发布商品、求购商品等。 三、部分…

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk)

MATLAB实现GARCH(广义自回归条件异方差)模型计算VaR(Value at Risk) 1.计算模型介绍 使用GARCH&#xff08;广义自回归条件异方差&#xff09;模型计算VaR&#xff08;风险价值&#xff09;时&#xff0c;方差法是一个常用的方法。GARCH模型能够捕捉到金融时间序列数据中的波…

动态规划 —— 子数组系列-乘积为正数的最长子数组长度

江河入海&#xff0c;知识涌动&#xff0c;这是我参与江海计划的第4篇。 1. 乘积为正数的最长子数组长度 题目链接&#xff1a; 1567. 乘积为正数的最长子数组长度 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/maximum-length-of-subarray-with-posit…

C语言-详细讲解-洛谷P1420 最长连号

1.题目要求 2.题目分析 考虑到说明里的数据规模&#xff0c;我们可以用动态内存分配来创建合适大小的数组&#xff0c;避免栈溢出问题&#xff0c;通过循环遍历&#xff0c;最终找到最长连号。 3.代码实现 #include <stdio.h> #include <stdlib.h>int main() {…

Python Matplotlib 数据可视化全面解析:选择它的七大理由与入门简介

Python Matplotlib数据可视化全面解析&#xff1a;选择它的七大理由与入门简介 本文介绍了Matplotlib这一强大而灵活的数据可视化工具&#xff0c;涵盖其基本概念、独特优势以及为何在众多Python绘图库中脱颖而出。Matplotlib具有广泛的社区支持、高度自定义能力、多样的绘图类…

《基于 PySpark 的电影推荐系统分析及问题解决》

以下是一篇关于上述代码的博客文章&#xff1a; 基于PySpark的电影推荐系统实现与分析 在当今数字化时代&#xff0c;个性化推荐系统在各个领域中都发挥着至关重要的作用&#xff0c;尤其是在娱乐行业&#xff0c;如电影推荐。本文将详细介绍如何使用PySpark构建一个简单的电…

ant-design-vue中table组件多列排序

antD中table组件多列排序 使用前注意实现效果图实现的功能点及相关代码1. 默认按某几个字段排序2. 点击排序按钮可同时对多个字段进行排序3. 点击重置按钮可恢复默认排序状态。 功能实现完整的关键代码 使用前注意 先要确认你使用的antD版本是否支持多列排序&#xff0c;我这里…

【华为】配置VXLAN构建虚拟网络实现相同网段互通(静态方式)

微思网络 厦门微思网络 组网需求 企业已经建成比较成熟的园区网络&#xff0c;但是没有专用的数据中心网络&#xff0c;所有的服务器分布在不同的部门&#xff0c;并且不具备集中放置的条件。现在用户希望在已有园区网络上构建一个虚拟网络&#xff0c;需求如下&#xff1a; 将…

神经网络问题之:梯度不稳定

梯度不稳定是深度学习中&#xff0c;特别是在训练深度神经网络时常见的一个问题&#xff0c;其本质涉及多个方面。 一、根本原因 梯度不稳定问题的根本原因在于深度神经网络的结构和训练过程中的一些固有特性。随着网络层数的增加&#xff0c;梯度在反向传播过程中会逐层累积变…

AI工具百宝箱|任意选择与Chatgpt、gemini、Claude等主流模型聊天的Anychat,等你来体验!

文章推荐 AI工具百宝箱&#xff5c;使用Deep Live Cam&#xff0c;上传一张照片就可以实现实时视频换脸...简直太逆天&#xff01; Anychat 这是一款可以与任何模型聊天 &#xff08;chatgpt、gemini、perplexity、claude、metal llama、grok 等&#xff09;的应用。 在页面…

云原生之k8s服务管理

文章目录 服务管理Service服务原理ClusterIP服务 对外发布应用服务类型NodePort服务Ingress安装配置Ingress规则 Dashboard概述 认证和授权ServiceAccount用户概述创建ServiceAccount 权限管理角色与授权 服务管理 Service 服务原理 容器化带来的问题 自动调度&#xff1a;…

Kafka 工作流程解析:从 Broker 工作原理、节点的服役、退役、副本的生成到数据存储与读写优化

Kafka&#xff1a;分布式消息系统的核心原理与安装部署-CSDN博客 自定义 Kafka 脚本 kf-use.sh 的解析与功能与应用示例-CSDN博客 Kafka 生产者全面解析&#xff1a;从基础原理到高级实践-CSDN博客 Kafka 生产者优化与数据处理经验-CSDN博客 Kafka 工作流程解析&#xff1a…

GitLab|数据迁移

注意&#xff1a;新服务器GitLab版本需和旧版本一致 在旧服务器执行命令进行数据备份 gitlab-rake gitlab:backup:create 备份数据存储在 /var/opt/gitlab/backups/ 将备份数据传输到新服务器的/var/opt/gitlab/backups/下&#xff0c;并修改文件权限&#xff08;下载前和上传…

开源项目低代码表单设计器FcDesigner获取表单的层级结构与组件数据

在使用开源项目低代码表单设计器FcDesigner时&#xff0c;获取和理解表单的层级结构非常关键。通过getDescription和getFormDescription方法&#xff0c;您可以清晰掌握表单组件的组织结构和层次关系。这些方法为操控表单的布局和配置提供了强大的支持。 源码地址: Github | G…

HDMI数据传输三种使用场景

视频和音频的传输 在HDMI传输音频中有3种方式进行传输&#xff0c;第一种将音频和视频信号被嵌入到同一数据流中&#xff0c;通过一个TMDS&#xff08;Transition Minimized Differential Signaling&#xff09;通道传输。第二种ARC。第三张种eARC。这三种音频的传输在HDMI线中…

解决IDEA中Maven管理界面不是层级结构的问题

文章目录 0. 前言1. 点击Maven管理界面右上角的三个点2. 勾选将模块分组3. 分组后的层级结构 更多 IDEA 的使用技巧可查看 IDEA 专栏中的文章&#xff1a;IDEA 0. 前言 在 IDEA 中&#xff0c;如果项目中有很多子模块&#xff0c;每个子模块中又有一个或多个子模块时&#xf…

GPT1.0 和 GPT2.0 的联系与区别

随着自然语言处理技术的飞速发展&#xff0c;OpenAI 提出的 GPT 系列模型成为了生成式预训练模型的代表。作为 GPT 系列的两代代表&#xff0c;GPT-1 和 GPT-2 虽然在架构上有着继承关系&#xff0c;但在设计理念和性能上有显著的改进。本文将从模型架构、参数规模、训练数据和…