【代码随想录】哈希

news2024/11/22 21:19:35

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.coloradmin.cn/o/2245557.html

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

相关文章

空间与单细胞转录组学的整合定位肾损伤中上皮细胞与免疫细胞的相互作用

result 在空间转录组图谱中对人类肾脏进行无监督映射和细胞类型鉴定 我们试图在H&E染色的人类参考肾切除标本组织切片上直接映射转录组特征。该组织来自一名59岁的女性&#xff0c;其肾小球闭塞和间质纤维化程度最低&#xff08;分别影响不到10%的肾小球或肾实质&#xff…

greater<>() 、less<>()及运算符 < 重载在排序和堆中的使用

简略图 greater<>()(a, b) a > b 返回true&#xff0c;反之返回false less<>()(a, b) a < b 返回true&#xff0c;反之返回false 在cmp中使用&#xff08;正着理解&#xff09; 规则返回true时a在前&#xff0c;反之b在前 在priority_queue中使用 &#xff…

详细描述一下Elasticsearch索引文档的过程?

大家好&#xff0c;我是锋哥。今天分享关于【详细描述一下Elasticsearch索引文档的过程&#xff1f;】面试题。希望对大家有帮助&#xff1b; 详细描述一下Elasticsearch索引文档的过程&#xff1f; Elasticsearch的索引文档过程是其核心功能之一&#xff0c;涉及将数据存储到…

入门车载以太网(6) -- XCP on Ethernet

目录 1.寻址方式 2.数据帧格式 3.特殊指令 4.使用实例 了解了SOME/IP之后&#xff0c;继续来看看车载以太网在汽车标定领域的应用。 在汽车标定领域XCP是非常重要的协议&#xff0c;咱们先来回顾下基础概念。 XCP全称Universal Measurement and Calibration Protocol&a…

Python中常用的函数介绍

Python中常用的几种函数 1、input函数 input()函数&#xff1a;主要作用是让用户输入某个内容并接收它。 #输入你的年龄 >>> age input("my age is :") my age is :20 执行代码后输入年龄&#xff0c;年龄被存放到age变量中&#xff0c;执行print后终端会…

Ubuntu从入门到精通(二)远程和镜像源配置齐全

Ubuntu从入门到精通(二) 1 常见操作配置 1.1 英文语言配置 1.1.1 打开设置 1.1.2 设置语言为英文 1.1.3 重启生效 1.1.4 再次进入,选择更新名字 1.1.5 再次进入,发现已经变成了英文 1.2 输入法配置 1.3 rustdesk安装 1.3.1 Windows系统配置 登陆:https://github.com…

卷积神经网络(CNN)中的池化层(Pooling Layer)

池化层&#xff08;Pooling Layer&#xff09;&#xff0c;也被称为下采样层&#xff0c;是深度学习神经网络中常用的一种层级结构。它通常紧跟在卷积层之后&#xff0c;对卷积层输出的特征图进行下采样操作。 一、定义与功能 池化层的主要作用是通过减少特征图的尺寸来降低计算…

【linux硬件操作系统】计算机硬件常见硬件故障处理

这里写目录标题 一、故障排错的基本原则二、硬件维护注意事项三、关于最小化和还原出厂配置四、常见故障处理及调试五、硬盘相关故障六、硬盘相关故障&#xff1a;硬盘检测问题七、硬盘相关故障&#xff1a;自检硬盘报错八、硬盘相关故障&#xff1a;硬盘亮红灯九、硬盘相关故障…

《操作系统》实验内容 实验二 编程实现进程(线程)同步和互斥(Python 与 PyQt5 实现)

实验内容 实验二 编程实现进程&#xff08;线程&#xff09;同步和互斥 1&#xff0e;实验的目的 &#xff08;1&#xff09;通过编写程序实现进程同步和互斥&#xff0c;使学生掌握有关进程&#xff08;线程&#xff09;同步与互斥的原理&#xff0c;以及解决进程&#xf…

智慧路面管理系统平台 智慧照明 智慧市政 智慧交通

智慧路面管理系统平台   智慧路面管理系统平台&#xff0c;旨在提高城市道路的智能化水平和交通效率。该系统通过集成传感器、摄像头、监控设备、大数据、云计算等多种技术手段&#xff0c;实现对道路状况和交通流量的实时监测与分析&#xff0c;从而提供精准的交通数据和智能…

数据结构 ——— 判断一棵树是否是完全二叉树

目录 满二叉树和完全二叉树示意图 手搓一个完全二叉树 代码实现 满二叉树和完全二叉树示意图 注意区分满二叉树和完全二叉树 满二叉树的每一层都是满的&#xff0c;也就是除了叶子节点&#xff0c;其他节点都有左右节点 完全二叉树的最后一层不一定是满的&#xff0c;但是从…

Vue_Router权限控制:不同角色显示不同路由

写在前面 在Vue中&#xff0c;Router是一个官方提供的用于处理应用程序路由的插件。它允许我们创建单页应用程序&#xff08;SPA&#xff09;&#xff0c;其中不同的页面和组件可以通过URL进行导航和展示。使我们可以轻松地创SPA&#xff0c;并实现可复用和可组合的组件…

java多线程并发执行方法或者调用接口

在开发过程中有时需要检查某个接口或者某个方法是否存在并发安全问题&#xff0c;我们会用到jmeter 、AB 等压测工具辅助我们完成代码测试&#xff0c;虽然这些工具功能很强大&#xff0c;也很好用&#xff0c;但是在开发过程中来使用还是不如直接执行Test 或者main 方法来的方…

Python小游戏28——水果忍者

首先&#xff0c;你需要安装Pygame库。如果你还没有安装&#xff0c;可以使用以下命令进行安装&#xff1a; 【bash】 pip install pygame 《水果忍者》游戏代码&#xff1a; 【python】 import pygame import random import sys # 初始化Pygame pygame.init() # 设置屏幕尺寸 …

测评部署和管理 WordPress 最方便的面板

新版宝塔面板快速搭建WordPress新手教程 - 倚栏听风-Morii - 博客园 初学者使用1Panel面板快速搭建WordPress网站 - 倚栏听风-Morii - 博客园 可以看到&#xff0c;无论是宝塔还是1Panel&#xff0c;部署和管理WordPress都有些繁琐&#xff0c;而且还需要额外去配置Nginx和M…

OpenAI Adjusts Strategy as ‘GPT’ AI Progress Slow

注&#xff1a;本文为两篇关于当前大模型方向讨论的文章。 OpenAI 大改下代大模型方向&#xff0c;scaling law 撞墙&#xff1f;AI 社区炸锅了 机器之心 2024 年 11 月 11 日 11:57 北京 机器之心报道 编辑&#xff1a;Panda、泽南 大模型的 scaling law 到头了&#xff1f…

Java开发者必备:23种设计模式全面解析

文章目录 一、创建型模式1、工厂模式简单工厂工厂方法 2、抽象工厂模式3、原型模式4、建造者模式5、单例模式 二、结构型模式1、适配器模式2、桥接模式3、组合模式4、装饰模式5、外观模式6、享元模式7、代理模式 三、行为型模式1、解释器模式2、模板方法模式3、策略模式4、观察…

LeetCode:1008. 前序遍历构造二叉搜索树

目录 题目描述: 代码: 第一种: 第二种: 第三种:分治法 题目描述: 给定一个整数数组&#xff0c;它表示BST(即 二叉搜索树 )的 先序遍历 &#xff0c;构造树并返回其根。 保证 对于给定的测试用例&#xff0c;总是有可能找到具有给定需求的二叉搜索树。 二叉搜索树 是一棵…

STM32F103 GPIO和串口实战

本节我们将会对STM32F103的硬件资源GPIO和串口进行介绍。 一、GPIO 1.1 电路原理图 LED电路原理图如下图所示&#xff1a; 其中&#xff1a; LED1连接到PA8引脚&#xff0c;低电平点亮&#xff1b;LED2连接到PD2引脚&#xff0c;低电平点亮&#xff1b; 1.2 GPIO引脚介绍 STM32…

Statsmodels之OLS回归

目录 Statsmodels基本介绍OLS 回归实战实战1&#xff1a;实战2&#xff1a; Statsmodels基本介绍 Statsmodels 是 Python 中一个强大的统计分析包&#xff0c;包含了回归分析、时间序列分析、假设检验等等的功能。Statsmodels 在计量的简便性上是远远不及 Stata 等软件的&…