代码随想录算法训练营第六天|242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

news2024/11/17 10:01:01

先了解一下什么是哈希表

哈希表是根据关键码的值而直接进行访问的数据结构

所以数组就是哈希表

盗个卡哥的图
哈希表中关键码就是数组的索引下标,然后通过下标直接访问数组中的元素,如下图所示:
在这里插入图片描述

哈希表能解决的问题:

一般哈希表都是用来快速判断一个元素是否出现集合里。
如果要查询一个名字是否在这所学校里,要枚举的话时间复杂度是O(n),但如果使用哈希表的话, 只需要O(1)就可以做到。

实际上我连枚举都没咋用过。。。

将学生姓名映射到哈希表上就涉及到了hash function ,也就是哈希函数。

哈希函数如下图所示,通过hashCode把名字转化为数值,一般hashcode是通过特定编码方式,可以将其他数据格式转化为不同的数值,这样就把学生名字映射为哈希表上的索引数字了。
在这里插入图片描述

哈希碰撞 数据结构上叫冲突

如果学生的数量大于哈希表的大小怎么办,此时就算哈希函数计算的再均匀,也避免不了会有几位学生的名字同时映射到哈希表 同一个索引下标的位置。

可以用拉链法和线性探测法解决

拉链法,就是在冲突的位置加个链表
在这里插入图片描述在这里插入图片描述其实拉链法就是要选择适当的哈希表的大小,这样既不会因为数组空值而浪费大量内存,也不会因为链表太长而在查找上浪费太多时间

而使用线性探测法就是需要有足够的表空间,来存放那些数据

哈希表教程

常用的三种哈希结构
数组,
set
map

242.有效的字母异位词

    • 先了解一下什么是哈希表
    • 哈希表能解决的问题:
    • 哈希碰撞 数据结构上叫冲突
    • 总结这两种暴力思路我认为都是讲字符串先排好队(无序到有序)然后再进行比较

题目链接

异位词的判断
判断两个字符串组成的字母是否相同,每个字母出现的次数是否一样,但位置可以不一样
比较好的暴力思维
第一种:先排序,用sort函数,然后再逐一对比,这就可以达到O(nlogn)了.

class Solution {
public:
    bool isAnagram(string s, string t) {
        //暴力解法
        //检验所给字符串的长度是否一致,这条你在考试的时候想不到也没事
        if(s.size()!=t.size())return false;
        //先排序
        sort(s.begin(),s.end());
        sort(t.begin(),t.end());
        for(int i=0;i<=s.size();i++){
            if(s[i]!=t[i])return false;
        }return true;

    }
};

第二种暴力思路,我也不知道这叫啥,枚举?
自己还没学过枚举…
就是建立两个数组,用来记录每个字符串中26个字母里的每个字母的出现次数,就是两个循环.最后再注意对比这两个数组的次数,感觉也是从无序到有序

class Solution {
public:
    bool isAnagram(string s, string t) {
        //暴力解法2
        //检验所给字符串的长度是否一致,这条你在考试的时候想不到也没事
        if(s.size()!=t.size())return false;
        //先建立两个数组
        vector <int> ss(26,0);//容器咋建数组又忘了
        vector <int> tt(26,0);
        //从头遍历字符串,统计每个字母出现的次数
        for(int i=0;i<s.size();i++){
            //ASCII码里,先是大写字母,然后是小写字母
            ss[s[i]-'a']++;
            tt[t[i]-'a']++;
        }
        for(int i=0;i<ss.size();i++){
            if(ss[i]!=tt[i])return false;
        }return true;

    }
};

有点牺牲空间换时间的意思但是这里的数组是固定的26,不随着字符串的长度儿变化,时间复杂度O(n)。空间复杂度O(1)
要记住时间复杂度不是开辟的空间大小比n大就是O(n)了而是与输入规模n有关的是O(n)否则是个无关常量不管大小为多少都为O(1)

总结这两种暴力思路我认为都是讲字符串先排好队(无序到有序)然后再进行比较

然后就是哈希的方法
看了看,跟第二个暴力也差不多少啊。。。。
就是处理方法不是比对相等,而是比对数组里的元素是否为0
这算是用数组下标来访问数组的元素,我想关键字是字符串的字符的值吧。
把字符映射到数组也就是哈希表的索引下标上

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

    }
};

349.两个数组的交集

    • 先了解一下什么是哈希表
    • 哈希表能解决的问题:
    • 哈希碰撞 数据结构上叫冲突
    • 总结这两种暴力思路我认为都是讲字符串先排好队(无序到有序)然后再进行比较

用了上面之前的暴力思想,把第一个数组可能出现的值放在统计数字出现次数的数组里,然后在第二个数组里检验,如果第二个数组中出现的数字在第一个数组里也出现了,那么这个数字就存在与交集, 但要特别注意的是要避免重复,两个数组都会有重复的数字,而在统计 交集的时候重复只能算一个,所以赋值只能是1,在比对第二个数组的时候,遇到了相同的数字就得改变其在记录数组的值,以免重复记录。

这个代码里用到了C++的容器的push_back()函数,将某数或某元素插入到数组末尾。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
        //自己的想法就是还是用一个1001个数的数组来记录两个数组的里的值
        //有点哈希的思想
        vector<int> record(1001,0);
        vector<int> result;
        for(int i=0;i<nums1.size();i++){
            record[nums1[i]]=1;
        }
        for(int i=0;i<nums2.size();i++){
            if(record[nums2[i]]==1)
            //别忘了nums2里也会有重复的元素
           { record[nums2[i]]=2;
            result.push_back(nums2[i]);}
        }return result;
        
    }
};

哈希:容器不能再选数组了
而且如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费

此时就要使用另一种结构体了,set ,关于set,C++ 给提供了如下三种可用的数据结构:

std::set   元素不能重复  有序集合
std::multiset   有序多重集合   元素可以重复
std::unordered_set   无序非重复集合   查找比set更快

std::set和std::multiset底层实现都是红黑树,std::unordered_set的底层实现是哈希表, 使用unordered_set 读写效率是最高的,并不需要对数据进行排序,而且还不要让数据重复,所以选择unordered_set。

本题交集结果不用考虑顺序

unordered_set 是 C++ 中的一个容器,它是哈希表的一种实现。与 set 相比,unordered_set 具有更快的查找速度,但是对于元素的顺序没有保证。unordered_set 中的元素是无序的,而且不能有重复的元素。

unordered_set 支持以下操作:

  • 插入元素:insert(key)
  • 删除元素:erase(key)
  • 查找元素:find(key),如果元素存在,则返回元素的迭代器,否则返回 unordered_set::end()
  • 判断元素是否存在:count(key),如果元素存在,则返回 1,否则返回 0;
  • 清空容器:clear()
  • 获取容器大小:size()
  • 判断容器是否为空:empty()

unordered_set 的底层实现是哈希表,因此插入、删除和查找元素的时间复杂度都是常数级别的 O(1),但是需要注意的是,如果哈希表出现冲突,这些操作的时间复杂度可能会退化为 O(n),其中 n 是哈希表中元素的个数。

给第一个数组的元素放入unordered_set里去重,
然后用第二个里的每个值与unordered_set 里的进行对比,如果这个值

   if (nums_set.find(num) != nums_set.end()) //这个啥意思啊

这段代码用来判断 nums2 中的元素是否在 nums1 中出现过,具体实现是通过在 nums_set 中查找是否存在该元素来判断。unordered_set 的 find 方法会返回指向存储该元素位置的迭代器,如果元素不存在,会返回一个指向 unordered_set 结尾的迭代器 end(),因此 nums_set.find(num) != nums_set.end() 的意思是:在 nums_set 中查找 num 元素,如果返回的迭代器不等于 end(),说明 num 存在于 nums_set 中,也就是 nums1 中出现过。

  for (int num : nums2)这个啥意思啊

这是C++11中的一种for循环语法,称为range-based for循环,也叫foreach循环,它可以用来遍历一个容器(如数组、vector等)中的所有元素。在这个例子中,nums2是一个容器(可能是数组或vector等),for循环会依次取出其中的每一个元素,赋值给变量num直接把数组里的值取出来赋给num了,而不是下标了。因此,这行代码的意思是依次取出nums2中的每一个元素,对于每一个元素,执行循环体中的语句。

class Solution {
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
      unordered_set<int>res;
      unordered_set<int>num(nums1.begin(),nums1.end());
      for(int i:nums2){
          if(num.find(i)!=num.end())
          res.insert(i);
      }return vector<int>(res.begin(),res.end());
    }
};

202.快乐数

    • 先了解一下什么是哈希表
    • 哈希表能解决的问题:
    • 哈希碰撞 数据结构上叫冲突
    • 总结这两种暴力思路我认为都是讲字符串先排好队(无序到有序)然后再进行比较

题目链接

主要是有一个数学上的问题,就是他这个会不会无限循环到无穷大
要从最大m位数即每位都是9,那么三位数就是243,4位是81*4.。。。。
这个会进入一个循环

在这里插入图片描述进入循环的就会出不去,这时我们选择用set来收集这些值,若有重复的就说明这个数不是快乐数,应该返回false

class Solution {
public:
 //如何一个多位数的各位之和
        //得用%求各位数的余数
        int getsum(int n){
            int sum=0;
            while(n){
                sum+=(n%10)*(n%10);
                n/=10;
            }return sum;
        }
        
    bool isHappy(int n) {
        set<int>num;
          int m=getsum(n);
        while(m!=1){
            if(num.find(m)!=num.end())//判断这个数在没在集合里
            return false;
            else {num.insert(m);
            m=getsum(m);//算新求的和的各位数的平方和,一直循环下去
            }
        }return true;

    }
};

两数之和

    • 先了解一下什么是哈希表
    • 哈希表能解决的问题:
    • 哈希碰撞 数据结构上叫冲突
    • 总结这两种暴力思路我认为都是讲字符串先排好队(无序到有序)然后再进行比较

题目链接

给你一个数,让你从数组里找出来两个数的和等于所给的这个数
1.这个数组是无序的,数组里允许有重复的值
如果有序还可以用这个前后指针,并且判断和的大小来决定移动哪个指针

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        //sort(nums.begin(),nums.end());
        int i=0,j=nums.size()-1;
        while(i<j){
        if(nums[i]+nums[j]==target)
            return {i,j};
        else if(nums[i]+nums[j]<target)
            i++;
            else j--;
        
    }return {i,j};
    }
    
};

无序的话用暴力就只能双重for循环了,这个题不包括用数组里的一个数加两次的情况

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
       int i,j;
       for( i=0;i<nums.size()-1;i++)
            for(int j=i+1;j<nums.size();j++)
                if(nums[i]+nums[j]==target)return {i,j};
                return {i,j};//不return 两次不通过啊,不知道为啥
      
       } 
    
};

时间复杂度O(n^2)
空间复杂度O(1)

1.为什么会想到用哈希表
2.哈希表为什么用map
3.本题map是用来存什么的
4.map中的key和value用来存什么的

当需要查询一个元素是否出现过,或者一个元素是否在集合里的时候

需要用一个集合来存放遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否遍历过,也就是 是否出现在这个集合。
key来存元素,value来存下标,那么使用map正合适
map是键值对,一个量保存下标,一个变量保存值
map也和set似的有三种类型
unordered_map为无序的,

所以哈希表的应用在容器里有三种,数组,set,map

map的一些基本用法
map{key 数据元素,value 值(数组元素对应的下标)}
map会自动按键值(key )大括号中的第一部分来排列顺序
其中key用迭代器->first
value 用迭代器->second

C++ STL之映射map的使⽤
map 是键值对,⽐如⼀个⼈名对应⼀个学号,就可以定义⼀个字符串string 类型的⼈名为“键”,学
号int 类型为“值”,如map<string, int> m; 
按照数组来说(前面是数组里的元素,下面是数组里的下标)
当然键、值也可以是其它变量类型~ 
map 会⾃动将所有的键值对按照键从⼩到⼤排序, 

map 使⽤时的头⽂件#include <map> 以下是map 中常⽤的⽅法:

#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
	map<string, int> m; // 定义⼀个空的map m,键是string类型的,值是int类型的
	
	m["hello"] = 2; // 将key为"hello", value为2的键值对(key-value)存⼊map中
	
	cout << m["hello"] << endl; // 访问map中key为"hello"的value, 如果key不存在,则返回0
	cout << m["world"] << endl;
	m["world"] = 3; // 将"world"键对应的值修改为3
	m[","] = 1; // 设⽴⼀组键值对,键为"," 值为1
	
// ⽤迭代器遍历,输出map中所有的元素,键⽤it->first获取,值⽤it->second获取
	for (auto it = m.begin(); it != m.end(); it++) {
	cout << it->first << " " << it->second << endl;
	}
	
	// 访问map的第⼀个元素,输出它的键和值
	cout << m.begin()->first << " " << m.begin()->second << endl;
	
	// 访问map的最后⼀个元素,输出它的键和值
	cout << m.rbegin()->first << " " << m.rbegin()->second << endl;

通俗的来讲整个做法就是每从数组里遍历一个数,就看看map里有没有能与之加一起为target的数。

pair<int, int>(nums[i], i):键值对,用pair来表示。<int,int>可以省略
pair是STL库提供的一个模板类,用于将两个值组合在一起,即一个键值对。
其中,pair<int, int>表示键值对中键和值的数据类型都是int,(nums[i], i)表示具体的键值对,
即nums[i]为键,i为值。

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
      unordered_map<int,int>map;
      for(int i=0;i<nums.size();i++){
          auto it=map.find(target-nums[i]);//迭代器,我就把它当成指针。。。
          if(it!=map.end()){//返回值,就是位置。
              return {it->second,i};
          }else map.insert(pair(nums[i],i));
      }
        return{};
       } 
    
};

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

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

相关文章

【LeetCode】987.二叉树的垂序遍历

二叉树遍历系列 144.二叉树的前序遍历94.二叉树的中序遍历145.二叉树的后续遍历102.二叉树的层序遍历107.二叉树的层序遍历II103.二叉树的锯齿形层序遍历&#xff08;之字形遍历&#xff09;199.二叉树的右视图 二叉树的垂序遍历目录 二叉树遍历系列1.问题示例 1示例 2示例 3 …

校招又临近了,怎么在面试中应对设计模式相关问题呢?

夏天开始了&#xff0c;那么夏天结束时的毕业季也不远了。毕业是个伤感、期待而又略带残酷的时节&#xff0c;就像蜜桃无论成熟与否都会在这个时间被采摘&#xff0c;如果毫无准备就踏入社会&#xff0c;就会……马上变成低级社畜。所以说还是要早点为了毕业找工作做点准备&…

Stereo-Detection:YOLO v5与双目测距结合,实现目标的识别和定位测距

简介&#xff1a;Stereo-Detection 是一个传统的SGBM深度测距yolov5目标检测&#xff0c;并部署在Jeston nano的开源教程。它致力于让更多的大四学生毕业&#xff0c;以及让研一学生入门 开源链接&#xff1a;yzfzzz/Stereo-Detection: Conventional SGBM depth ranging yolov…

【android专题】学习android,第一天学习:软件和组件了解

开发软件和手机建立连接 1.建立连接 2.运行App程序到手机&#xff0c;通过USB线 选择你的小米设备 run按钮 下面这个&#xff0c;就是你设备的日志 通过USB安装时&#xff0c;报错&#xff0c;大概意思就是&#xff0c;默认手机是禁止通过usb安装软件的&#xff0c; 要打开…

Automa自动化爬取图片(二)

Automa插件可以扩展Automa的功能&#xff0c;使其可以与其他应用程序进行交互。例如&#xff0c;Automa插件可以用于自动化测试Web应用程序&#xff0c;批量发送邮件&#xff0c;自动化填写表单等。通过Automa插件&#xff0c;我们可以更加灵活地定制自己的自动化测试工具&…

Linux 配置YUM源(FTP方式获取软件源、使用阿里云yum源、同时使用本地源与在线源)YUM获取安装包并生成YUM软件仓库

YUM介绍 YUM&#xff08;yellow dog updater modified&#xff09; 基于RPM包构建的软件更新机制 自动解决依赖关系 yum软件仓库集中管理软件包 RPM软件包的来源 centos发布的RPM包集合第三方组织发布的RPM包集合用户自定义的RPM包集合 软件仓库的提供方式 FTP服务&#xff1a;…

阿里4年测试经验分享 —— 测试外包干了3年后,我废了...

去年国庆&#xff0c;我分享了一次一位阿里朋友的技术生涯&#xff0c;大家反响爆蓬&#xff0c;感觉十分有意思&#xff0c;今天我来分享一下我另一位朋友的真实经历&#xff0c;是不是很想听&#xff1f; 没错&#xff0c;我这位朋友是曾经外包公司的测试开发&#xff0c;而…

SAPJNet:小样本多序列MRI诊断的序列自适应原型联合网络

文章目录 SAPJNet: Sequence-Adaptive Prototype-Joint Network for Small Sample Multi-sequence MRI Diagnosis摘要方法Sequence-Adaptive Transformer原型优化策略 实验结果 SAPJNet: Sequence-Adaptive Prototype-Joint Network for Small Sample Multi-sequence MRI Diagn…

【2023-4-8 美团春招笔试题 开发岗(技术综合-后端数开软开)】

题目一&#xff1a; 代码一&#xff1a; #include <iostream> #include <string> using namespace std;int main() {int n,m,a;cin>>n>>m>>a;string s[n][m];for(int i0;i<n;i){for(int j0;j<m;j){cin>>s[i][j];}}int count0;for(i…

【MySQL】(7)复合查询

文章目录 单表查询回顾与练习多表查询自连接多行子查询&#xff08;单列&#xff09;in 运算符all 关键字any 关键字 多列子查询from 子句中的子查询合并查询 单表查询回顾与练习 注&#xff1a;下面的依旧基于 scott 数据库 MariaDB [scott]> select * from emp; -------…

【历史上的今天】4 月 23 日:YouTube 上传第一个视频;数字音频播放器的发明者出生

整理 | 王启隆 透过「历史上的今天」&#xff0c;从过去看未来&#xff0c;从现在亦可以改变未来。 今天是 2023 年 4 月 23 日&#xff0c;世界读书日。在 1564 年的这一天&#xff0c;全世界最卓越的文学家之一莎士比亚出生&#xff1b;1616 年的这一天&#xff0c;莎士比亚…

ubuntu22.04普通用户配置cuda

ubuntu22.04普通用户配置cuda 1. 问题描述2. 解决方法2.1 查看安装cuda版本2.2 修改普通用户自己的环境变量2.3 重新执行初始化文档2.4 查看nvcc版本&#xff0c;测试是否成功 1. 问题描述 在ubuntu22.04服务器上使用root用户安装了cuda&#xff0c;普通用户登录时仍然没办法直…

中国社科院与美国杜兰大学金融管理硕士项目——你永远可以,成为想要的自己

有人说过&#xff0c;世界上最好的保鲜就是不断进步&#xff0c;每一次改变都是新生的开始&#xff0c;让自己成为更好的更值得爱的人。你要相信&#xff0c;不论任何时候&#xff0c;你都可以成为想要的自己。就像我们在职攻读硕士学位&#xff0c;经过在社科院与杜兰大学金融…

聚观早报|周鸿祎360员工不会被GPT淘汰;蚂蚁集团再捐1亿种树治沙

今日要闻&#xff1a;周鸿祎称360员工不会被GPT淘汰&#xff1b;特斯拉ModelS/X美国售价全系上涨&#xff1b;蚂蚁集团再捐1亿支持种树治沙&#xff1b;复旦大学MOSS大模型正式开源&#xff1b;电影《灌篮高手》票房突破2亿元 周鸿祎称360员工不会被GPT淘汰 4 月 21 日下午&am…

链表中的递归算法C语言带你看看

25. K 个一组翻转链表 难度困难1998收藏分享切换为英文接收动态反馈 给你链表的头节点 head &#xff0c;每 k 个节点一组进行翻转&#xff0c;请你返回修改后的链表。 k 是一个正整数&#xff0c;它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍&#xff0c;那么…

Redis实现分布式锁的正确姿势 | Spring Cloud 36

一、分布式锁 1.1 什么是分布式锁 分布式锁&#xff0c;即分布式系统中的锁。在单体应用中我们通过锁解决的是控制共享资源访问的问题&#xff0c;而分布式锁&#xff0c;就是解决了分布式系统中控制共享资源访问的问题。与单体应用不同的是&#xff0c;分布式系统中竞争共享…

【网络安全】SSRF漏洞

ssfr ssrf产生的原因原理展示使用不当可能出现ssrf漏洞函数漏洞检测(靶场一)代码curl是什么检测服务器是否可以从其他服务器获取数据使用file协议获取远端服务器的内容利用dict协议探测端口 漏洞检测&#xff08;靶场二&#xff09;代码file_get_contents()利用file协议读取服务…

过来人(江苏)专转本考试后的感悟和经验,真的很受用

过来人转本考试后的感悟和经验&#xff0c;真的很受用&#xff01; 转本不仅是分数的较量&#xff0c;也是信息收集、时间管理、学习能力、毅力等等的较量。 同学们在转本中难免会遇见一些困难&#xff0c;为了避免走弯路&#xff0c;一起来看看过来人的感悟和经验吧&#xf…

Android音频使用webrtc降噪处理、回声消除

Android音频使用webrtc降噪处理、回声消除 介绍音频处理在Android应用中的重要性和应用场景 音频处理在Android应用中扮演着重要的角色&#xff0c;它能够改善用户体验&#xff0c;提升应用的功能性和吸引力。下面将介绍音频处理在Android应用中的广泛应用以及音频处理对用户体…

深度学习--基础(一)pytorch安装--cpu

在线安装 无GPU的时候&#xff0c;只能安装CPU版本&#xff0c;打开官网 https://pytorch.org/ 直接Pip安装即可 国内访问这些下载安装会出现超时的情况&#xff0c;可以-i指定国内安装源&#xff1a; pip3.11 install torch torchvision torchaudio -i https://pypi.tuna.ts…