代码随想录-哈希表|ACM模式

news2024/11/25 9:45:17

目录

前言:

(1)基本概念

(2)常见的三种哈希结构

242.有效字母的异位词

题目描述:

输入输出描述:

思路和想法:

349. 两个数组的交集

题目描述:

输入输出描述:

思路和想法:

202. 快乐数

题目描述:

输入输出描述:

思路和想法:

1. 两数之和

题目描述:

输入输出描述:

思路和想法:

454. 四数相加 II

题目描述:

输入输出描述:

思路和想法:

383. 赎金信

题目描述:

输入输出描述:

思路和想法


前言:

(1)基本概念

就是用哈希函数构建索引和内容之间的映射。就相当于一个内容就会有相对应的哈希函数值(即索引下标),直接找下标,就能查询是否有相应的内容。

在这个过程中,可能会遇到两个同时映射到一个,这个就是哈希碰撞的现象,应对这个方法常见的有两种,其中一个是拉链法(即采用链表的方式),另一个就是线性探测法。

①拉链法需要选择适当的哈希表的大小----不会因为数组空值而浪费大量内存,另一个不会链表太长而在查找上浪费太多时间。

②线性探测法,一定要保证tablesize大于datasize。依靠哈希表空位来解决碰撞问题。

(2)常见的三种哈希结构

数组、set(集合)以及map(映射)

242.有效字母的异位词

题目描述:

给定两个字符串 st ,编写一个函数来判断 t 是否是 s 的字母异位词。

注意:st 中每个字符出现的次数都相同,则称 st 互为字母异位词。

输入输出描述:

示例 1:

输入: s = "anagram", t = "nagaram" 输出: true

示例 2:

输入: s = "rat", t = "car" 输出: false

提示:

  • 1 <= s.length, t.length <= 5 * 104
  • s 和 t 仅包含小写字母

思路和想法:

这个问题可以分为三个步骤来解决。

  • 步骤一:构建Hash table-数组,之后遍历第一个字符串将里面的元素一一对应到哈希表上记录频次。
  • 步骤二:再遍历第二个字符串,将相应位置--。
  • 步骤三:最终只需判断哈希表内元素是否都为零,就可以判断这两个字符串是否互为有效字母异位词。
#include <bits/stdc++.h>
using namespace std;
bool isAnagram(string s, string t) {
    //将a-z,26个字母到0-25
    //哈希表
    unordered_map<int, int> m;
    for(int i = 0; i < s.size(); i++ ){
        m[s[i]-'a']++;
    }
    for(int i = 0; i < t.size(); i++){
        m[t[i]-'a']--;
    }
    for(int i = 0; i < 26;i++){
        if(m[i] != 0) return false;
    }
    return true;
}
int main() {
    string s,t;
    getline(cin,s);
    getline(cin,t);

    bool result;
    result = isAnagram(s,t);

    if(result == 1){
        cout << "true";
    }else{
        cout << "false";
    }
    return 0;
}
/************
示例1:
anagram
nagaram
示例2:
rat
car
*************/

349. 两个数组的交集

题目描述:

给定两个数组 nums1 和 nums2 ,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序

输入输出描述:

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2] 输出:[2]

示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] 输出:[9,4] 解释:[4,9] 也是可通过的

提示:

  • 1 <= nums1.length, nums2.length <= 1000
  • 0 <= nums1[i], nums2[i] <= 1000

思路和想法:

可以清晰的知道我们要判断元素在集合中是否出现过。这里数值较大,适合采用set的方式,并且非重复,考虑时间复杂度和空间复杂度,采用unordered_set。

将第一个数组进行处理转换成set,再用numbers2遍历查询是否出现过,放在result集合里。

#include <bits/stdc++.h>
using namespace std;

vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
    unordered_set <int> result;
    unordered_set <int> nums_set(nums1.begin(), nums1.end());    //将数组1转换成哈希表

    for(int i = 0; i < nums2.size(); i++){
        if(nums_set.find(nums2[i]) != nums_set.end()){
            result.insert(nums2[i]);                            //set插入元素操作
        }
    }
    return vector <int> (result.begin(), result.end());

}

int main() {
    vector<int> nums1,nums2;
    int num;
    //nums1
    while(cin >> num) {
        nums1.push_back(num);
        // 读到换行符,终止循环
        if(getchar() == '\n') {
            break;
        }
    }
    //nums2
    while(cin >> num) {
        nums2.push_back(num);
        // 读到换行符,终止循环
        if(getchar() == '\n') {
            break;
        }
    }

    vector<int> result;
    result = intersection(nums1,nums2);

    for(int i = 0; i < result.size(); i++) {
        cout << result[i] << " ";
    }
    cout << endl;
    return 0;
}
/*************
示例1:
1 2 2 1
2 2
示例2:
4 9 5
9 4 9 8 4
 ************/

202. 快乐数

题目描述:

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

输入输出描述:

示例 1:

输入:n = 19 输出:true 解释: 12 + 92 = 82 82 + 22 = 68 62 + 82 = 100 12 + 02 + 02 = 1

示例 2:

输入:n = 2 输出:false

提示:

  • 1 <= n <= 2^31 - 1

思路和想法:

这里比较重要的地方,在于判断什么时候出现无限循环,即判断平方和数值重复出现。这里就是判断元素有无重复出现,就可以set来解决了。解决这道题目具体的步骤如下:

步骤一:计算数n的各个位置的平方和

步骤二:判断是否出现了1,并进行循环,如果在这个过程中,在set集合中找到元素,则证明出现循环,return false。

#include <bits/stdc++.h>
using namespace std;

int Sum(int n){
    int sum = 0;
    while(n){
        sum += (n % 10) * (n % 10);
        n /= 10;
    }
    return sum;
}

bool isHappy(int n) {
    unordered_set<int> set;
    while(1){
        int sum1 = Sum(n);
        if(sum1 == 1){
            return true;
        }
        if (set.find(sum1) != set.end()) {
            return false;
        } else {
            set.insert(sum1);
        }
        n = sum1;
    }
}

int main() {
    int number;
    cin >> number;

    bool result;
    result = isHappy(number);

    if(result == 1){
        cout << "true" <<endl;
    }else{
        cout << "false" <<endl;
    }

    return 0;
}
/*************
示例1:
19
true
示例2:
2
false
 ************/

1. 两数之和

题目描述:

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

输入输出描述:

示例 1:

输入:nums = [2,7,11,15], target = 9 输出:[0,1] 解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:

输入:nums = [3,2,4], target = 6 输出:[1,2]

示例 3:

输入:nums = [3,3], target = 6 输出:[0,1]

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案

思路和想法:

在判断元素有无的同时,也要存储下标,所以这里我们采用unorderded_map。其中map结构--key(元素),value(下标)。

#include <bits/stdc++.h>
using namespace std;

vector<int> twoSum(vector<int>& nums, int target) {
    unordered_map <int,int> map;
    for(int i = 0; i < nums.size(); i++) {
        // 遍历当前元素,并在map中寻找是否有匹配的key
        auto iterm = map.find(target - nums[i]);
        if(iterm != map.end()) {
            return {iterm->second, i};
        }
        // 如果没找到匹配对,就把访问过的元素和下标加入到map中
        map.insert(pair<int, int>(nums[i], i));
    }
    return {};
}

int main() {
    vector<int> nums;
    int num;
    while(cin >> num){
        nums.push_back(num);
        if(getchar() == '\n'){
            break;
        }
    }

    int target;
    cin >> target;
    vector<int> result;
    result = twoSum(nums,target);

    for (int i = 0; i < result.size(); ++i) {
        cout << result[i] << " ";
    }
    cout << endl;
    return 0;
}
/*************
示例1:
2 7 11 15
9
示例2:
3 2 4
6
示例3:
3 3
6
 ************/

454. 四数相加 II

题目描述:

给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

输入输出描述:

示例 1:

输入:nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2] 输出:2

解释: 两个元组如下: 1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0 2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

示例 2:

输入:nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0] 输出:1

提示:

  • n == nums1.length
  • n == nums2.length
  • n == nums3.length
  • n == nums4.length
  • 1 <= n <= 200
  • -2^28 <= nums1[i], nums2[i], nums3[i], nums4[i] <= 2^28

思路和想法:

将四个数组简化成两个数组,并将其中一个放入map中,key放两两数组加和值,value放数组下标。

步骤一:先构建一个哈希表(nums1),存储key以及value,key对应数组之和,value记录次数。

步骤二:nums3 + nums4,进行map查询,寻找里面是否有其相反数的映射。

#include <bits/stdc++.h>
using namespace std;

int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
    std::unordered_map<int, int> h1;
    //步骤一,构建哈希表,存储key以及value
    int size = nums1.size();
    int sum = 0;                //key---数组两两加和值
    int Ycount = 0;             //记录多少个元组满足
    for(int i = 0; i < size; i++){
        for(int j = 0; j < size; j++){
            sum = nums1[i] + nums2[j];
            h1[sum]++;
        }
    }
    //步骤二,map查询,记录次数
    for(int i = 0; i < size; i++){
        for(int j = 0; j < size; j++){
            sum = nums3[i] + nums4[j];
            auto item = h1.find(-sum);
            if(item != h1.end()){
                Ycount += h1[-sum];
            }
        }
    }
    return Ycount;
}

int main() {
    int n;
    cin >> n;
    vector<int> n1(n),n2(n),n3(n),n4(n);
    for (int i = 0; i < n; ++i) {
        cin >> n1[i];
    }
    for (int i = 0; i < n; ++i) {
        cin >> n2[i];
    }
    for (int i = 0; i < n; ++i) {
        cin >> n3[i];
    }
    for (int i = 0; i < n; ++i) {
        cin >> n4[i];
    }

    int result;
    result = fourSumCount(n1,n2,n3,n4);
    cout << result << endl;

    return 0;
}
/*************
示例1:
2
1 2
-2 -1
-1 2
0 2
示例2:
1
0
0
0
0
 ************/

383. 赎金信

题目描述:

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

输入输出描述:

示例 1:

输入:ransomNote = "a", magazine = "b" 输出:false

示例 2:

输入:ransomNote = "aa", magazine = "ab" 输出:false

示例 3:

输入:ransomNote = "aa", magazine = "aab" 输出:true

提示:

  • 1 <= ransomNote.length, magazine.length <= 105
  • ransomNote 和 magazine 由小写英文字母组成

思路和想法:

这里分为三个步骤。

  • 步骤一:用哈希数组记录magzine字母出现次数
  • 步骤二:遍历ransomNote,消耗magzine
  • 步骤三:判断magzine是否透支(有负数),是则返回false
#include <bits/stdc++.h>
using namespace std;

bool canConstruct(string ransomNote, string magazine) {
    //因为magzine只由小写字母组成,26,采用数组哈希解决最好,不占空间的同时,查询时间也很短
    int h1[26] = {0};
    //步骤一,进行遍历,记录字母出现次数
    for(int i = 0; i < magazine.size(); i++){
        h1[magazine[i]-'a']++;
    }

    //步骤二:再对ransomNote进行遍历,对应--
    for(int i = 0; i < ransomNote.size(); i++ ){
        h1[ransomNote[i]-'a']--;
    }
    //步骤三:对数组遍历,看其是否存在负数,存在return false
    for(int i = 0; i < 26;i++){
        if(h1[i] < 0) return false;
    }
    return true;
}

int main() {
    string str1,str2;
    getline(cin,str1);
    getline(cin,str2);

    bool result;
    result = canConstruct(str1,str2);

    if(result == 1){
        cout << "true" << endl;
    }else{
        cout << "false" << endl;
    }

    return 0;
}
/*************
示例1:
a
b
示例2:
aa
ab
示例3:
aa
aab
 ************/

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

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

相关文章

Mac上如何修复损坏的音频?试试iZotope RX 10,对音频进行处理,提高音频质量!

iZotope RX 10是一款由iZotope公司开发的音频修复和编辑软件。它被广泛用于电影、电视、音乐和游戏等行业的音频后期制作&#xff0c;以及声音设计和修复工作。 在RX 10中&#xff0c;iZotope从头开始重新设计了全新的Repair Assistant修复助手&#xff0c;并且推出了相应的修…

嵌入式学习笔记(40)看门狗定时器

7.5.1什么是看门狗、有何用 (1)看门狗定时器和普通定时器并无本质区别。定时器可以设定一个时间&#xff0c;在这个时间完成之前定时器不断计时&#xff0c;时间到的时候定时器会复位CPU&#xff08;重启系统&#xff09;。 (2)系统正常工作的时候当然不希望被重启&#xff0…

【小沐学前端】Node.js实现基于Protobuf协议的UDP通信(protobuf.js)

文章目录 1、简介1.1 node1.2 Protobuf 2、下载和安装2.1 node2.2 Protobuf2.2.1 安装2.2.2 工具 3、node 代码示例3.1 HTTP3.2 UDP单播3.4 UDP广播 4、Protobuf 代码示例4.1 例子: awesome.proto4.1.1 加载.proto文件方式4.1.2 加载.json文件方式4.1.3 加载.js文件方式 4.2 例…

vSAN7.0更换硬盘步骤

更换容量盘 预先检查 查看故障硬盘 清单->集群->监控->vsan->skyline运行->物理磁盘->运维运行状况 检查数据同步状态 清单->集群->监控->vsan->重新同步对象&#xff0c;数值全为0表示未重建。 数据迁移检查 清单->集群->监控->…

推荐算法——Apriori算法原理

0、前言&#xff1a; 首先名字别读错&#xff1a;an pu ruo ao rui 【拼音发音】Apriori是一种推荐算法推荐系统&#xff1a;从海量数据中&#xff0c;帮助用户进行信息的过滤和选择。主要推荐方法有&#xff1a;基于内容的推荐、协同过滤推荐、基于关联规则的推荐、基于知识的…

八大排序源码(含优化)

文章目录 1、直接插入排序2、希尔排序3、选择排序4、冒泡排序5、堆排序6、快速排序快速排序递归实现霍尔法挖坑法前后指针法快速排序小区间优化 快速排序非递归实现 7、归并排序归并排序递归实现归并排序非递归 8、计数排序 大家好&#xff0c;我是纪宁&#xff0c;这篇文章是关…

36.骑士周游算法及其基于贪心算法的优化

概述 骑士周游算法&#xff0c;叫做“马踏棋盘算法”或许更加直观。在国际象棋8x8的棋盘中&#xff0c;马也是走“日字”进行移动&#xff0c;相应的产生了一个问题&#xff1a;“如果要求马 在每个方格只能进入一次&#xff0c;走遍全部的64个方格需要如何行进&#xff1f;”…

【STM32基础 CubeMX】按键的检测

文章目录 前言一、按键原理图分析二、cubeMX配置key GPIO三、代码分析3.1 cubemx生成的代码3.2 1个库函数 四、按键点灯示例代码总结 前言 在嵌入式系统开发中&#xff0c;按键检测是一个基础而重要的任务&#xff0c;特别是在使用STM32系列微控制器的项目中。按键通常被用于与…

C++ - 开放地址法的哈希介绍 - 哈希表的仿函数例子

前言 哈希其实是一种搜索方式&#xff0c;像暴力查找&#xff0c;有序数组的二分查找&#xff0c;二分查找就很快了&#xff0c;可以达到O(log n)。但是有序数组有一个 弊端&#xff0c;就是要先进行排序&#xff0c;这就有消耗&#xff0c;这还好&#xff0c;当要插入删除修改…

Go-Python-Java-C-LeetCode高分解法-第八周合集

前言 本题解Go语言部分基于 LeetCode-Go 其他部分基于本人实践学习 个人题解GitHub连接&#xff1a;LeetCode-Go-Python-Java-C 欢迎订阅CSDN专栏&#xff0c;每日一题&#xff0c;和博主一起进步 LeetCode专栏 本文部分内容来自网上搜集与个人实践。如果任何信息存在错误,欢迎…

UE5.1编辑器拓展【一、脚本化资产行为,通知,弹窗,高效复制多个同样的资产】

目录​​​​​​​ 插件制作 添加新的类&#xff1a;AssetActionUtility 添加新的模块&#xff1a;EditorScriptingUtilities 路径了解 添加debug的头文件 代码【debug.h】内涵注释&#xff1a; 写函数 .h文件 .cpp文件 插件制作 首先第一步是做一个插件&#xff1a…

Flink中序列化RoaringBitmap不同方式的对比

背景 在flink中&#xff0c;我们有时候会使用到RoaringBitmap进行统计计数等操作&#xff0c;而当使用RoaringBitmap时&#xff0c;这就涉及到了最重要的问题&#xff0c;如何序列化&#xff1f;序列化的目的是为了进行网络通信或者状态序列化的目的&#xff0c;本文的重点是比…

根据GWAS数据估算样本量N和使用千人基因组填充maf的参考文献

https://github.com/GenomicSEM/GenomicSEM/wiki/2.1-Calculating-Sum-of-Effective-Sample-Size-and-Preparing-GWAS-Summary-Statistics

【LeetCode热题100】--104.二叉树的最大深度

104.二叉树的最大深度 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) …

尚硅谷谷粒商城部分报错问题处理

1、启动报错&#xff1a; 内容&#xff1a; org.springframework.beans.factory.BeanCreationException: Error creating bean with name attrAttrgroupRelationController: Lookup method resolution failed; nested exception is java.lang.IllegalStateException: Failed t…

使用prometheus监控java服务

在prometheus官方下载页面没有看到jvm_exproter的下载地址但是官方页面是有推荐下载地址的 访问 Prometheus - Monitoring system & time series database prometheus官方网址 官方推荐地址下载是在github网络访问不方便的可以用下面的网址 wget https://repo1.maven…

【小程序 - 基础】页面导航、页面事件、生命周期、WXS脚本_04

目录 一、页面导航 1. 什么是页面导航 2. 小程序中实现页面导航的两种方式 2.1 声明式导航 2.1.1 导航到 tabBar 页面 2.1.2 导航到非 tabBar 页面 2.1.3 后退导航 2.2 编程式导航 2.2.1 导航到 tabBar 页面 2.2.2 导航到非 tabBar 页面 2.2.3 后退导航 2.3. 导航…

Proxyer实现内网穿透云服务器

Proxyer Proxyer是一个网络代理工具&#xff0c;它可以将本地计算机的网络流量&#xff08;如HTTP、HTTPS、TCP等&#xff09;转发到远程服务器。使用Proxyer可以在本地计算机上建立一个代理服务器&#xff0c;通过代理服务器来访问互联网上的资源。 yum仓库设置 rm -f /etc…

在Ubuntu上通过Portainer部署微服务项目

这篇文章主要记录自己在ubuntu上部署自己的微服务应用的过程&#xff0c;文章中使用了docker、docker-compose和portainer&#xff0c;在部署过程中遇到了不少问题&#xff0c;因为博主也是初学docker-compose&#xff0c;通过这次部署实战确实有所收获&#xff0c;在这篇文章一…

LeetCode【121. 买卖股票的最佳时机】

你才不是什么小人物&#xff0c;你在我这里&#xff0c;是所有的天气和心情。 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票&#xff0c;并选择在 未来的某一个不同的日子 卖出该股票。设计一…