哈希表算法练习
1. 有效的字母异位词
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
示例 1:
输入: s = "anagram", t = "nagaram"
输出: true
示例 2:
输入: s = "rat", t = "car"
输出: false
说明: 你可以假设字符串只包含小写字母
代码如下:
点击查看代码
#include <iostream>
#include <unordered_map>
using namespace std;
bool IsSameWord(const string s, const string t)
{
if (s.size() != t.size() || !s.size()) return false;
unordered_map<char, int> map;
for (int i = 0; i < s.size(); ++i)
{
++map[s[i]];
--map[t[i]];
}
for (const auto& m : map)
{
if (m.second) return false;
}
return true;
}
int main()
{
string s = "anagram", t = "nagaram";
cout << IsSameWord(s, t) << endl;
return 0;
}
2. 两个数组的交集
给定两个数组,编写一个函数来计算它们的交集。
示例 1:
输入:nums1=[1,2,2,1],nums2 =[2,2]
输出:[2]
示例 2:
输入:nums1=[4,9,5],nums2=[9,4,9,8,4]
输出:[9,4]
说明: 输出结果中的每个元素一定是唯一的。 我们可以不考虑输出结果的顺序。
代码如下:
点击查看代码
#include<iostream>
#include<unordered_set>
#include<vector>
using namespace std;
vector<int> findCrossArr(const vector<int>& nums1, const vector<int>& nums2)
{
unordered_set<int> set(nums1.begin(), nums1.end());
unordered_set<int> ans;
for (const auto& n : nums2)
{
if (set.count(n))
ans.insert(n);
}
return vector<int>(ans.begin(), ans.end());
}
void showArr(const vector<int>& nums)
{
cout << '[';
for (int i = 0; i < nums.size(); ++i)
{
cout << nums[i];
if (i != nums.size() - 1)
cout << ',';
}
cout << ']' << endl;
}
int main()
{
vector<int> nums1 = {4,9,5};
vector<int> nums2 = {9,4,9,8,4};
showArr(findCrossArr(nums1, nums2));
return 0;
}
3. 快乐数
编写一个算法来判断一个数 n 是不是快乐数。
快乐数 定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果 可以变为 1,那么这个数就是快乐数。
如果 n 是快乐数就返回 True ;不是,则返回 False 。
示例:
输入:19
输出:true
解释:
1^2 + 9^2 = 82
8^2 + 2^2 = 68
6^2 + 8^2 = 100
1^2 + 0^2 + 0^2 = 1
代码如下:
点击查看代码
#include<iostream>
#include<cmath>
#include<unordered_set>
using namespace std;
/*
这道题目使用哈希法,来判断这个sum是否重复出现,
如果重复了就是return false, 否则一直找到sum为1为止。
*/
bool IsHappyNumber(int n)
{
int sum = 0;
string num = to_string(n);
unordered_set<int> set;
while (1)
{
sum = 0;
for (auto n : num)
{
sum += pow((n - '0'), 2);
}
if (sum == 1)
return true;
if (set.count(sum))
return false;
set.insert(sum);
num = to_string(sum);
}
}
int main()
{
int n;
cin >> n;
string ans = IsHappyNumber(n) ? "true" : "false";
cout << ans << endl;
return 0;
}
4. 两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
代码如下:
点击查看代码
#include"../tools.h"
#include<unordered_map>
vector<int> findSumIndex(const vector<int>& nums, const int target)
{
unordered_map<int, int> map;
// 遍历当前元素,并在map中寻找是否有匹配的key
for (int i = 0; i< nums.size(); ++i)
{
if(map.find(target - nums[i]) != map.end())
return {i, map.find(target - nums[i])->second};
// 如果没找到匹配对,就把访问过的元素和下标加入到map中(避免了元素重复使用)
map[nums[i]] = i;
}
return {};
}
int main()
{
vector<int> nums = {3,2,4};
int target = 6;
showArr(findSumIndex(nums, target));
return 0;
}
5. 四数相加II
给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。
所有整数的范围在 -2^28 到 2^28 - 1 之间,最终结果不会超过 2^31 - 1 。
例如:
输入:
A = [ 1, 2]
B = [-2,-1]
C = [-1, 2]
D = [ 0, 2]
输出:
2
解释:
两个元组如下:
(0, 0, 0, 1) -> A[0] + B[0] + C[0] + D[1] = 1 + (-2) + (-1) + 2 = 0
(1, 1, 0, 0) -> A[1] + B[1] + C[0] + D[0] = 2 + (-1) + (-1) + 0 = 0
代码如下:
点击查看代码
#include"../tools.h"
#include<unordered_map>
int findFourArrSum(const vector<int>& num1, const vector<int>& num2,
const vector<int>& num3, const vector<int>& num4)
{
int count = 0;
unordered_map<int, int> map;
// 记录和次数
for (const auto& n1 : num1)
{
for (const auto& n2 : num2)
{
++map[n1 + n2];
}
}
// 匹配和为 0
for (const auto& n3 : num3)
{
for (const auto& n4 : num4)
{
if (map.find(0 - (n3 + n4)) != map.end())
count += map[0 - (n3 + n4)];
}
}
return count;
}
int main()
{
vector<int> A = {1,2};
vector<int> B = {-2,-1};
vector<int> C = {-1,2};
vector<int> D = {0,2};
cout << findFourArrSum(A, B, C, D) << endl;
return 0;
}
6. 赎金信
给定一个赎金信 (ransom) 字符串和一个杂志(magazine)字符串,
判断第一个字符串 ransom 能不能由第二个字符串 magazines 里面的字符构成。
如果可以构成,返回 true ;否则返回 false。
(题目说明:为了不暴露赎金信字迹,要从杂志上搜索各个需要的字母,
组成单词来表达意思。杂志字符串中的每个字符只能在赎金信字符串中使用一次。)
注意:
你可以假设两个字符串均只含有小写字母。
canConstruct("a", "b") -> false
canConstruct("aa", "ab") -> false
canConstruct("aa", "aab") -> true
代码如下:
点击查看代码
#include"../tools.h"
#include<unordered_map>
bool canConstruct(const string& ran, const string& mag)
{
if (ran.size() > mag.size())
return false;
unordered_map<char, int> map;
for (const auto& c : mag)
++map[c];
for (const auto& c : ran)
{
if(!map.count(c) || --map[c] < 0)
return false;
}
return true;
}
int main()
{
string ran = "aa", mag = "ab";
cout << canConstruct(ran, mag) << endl;
return 0;
}
7. 三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?
请你找出所有满足条件且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
示例:
给定数组 nums = [-1, 0, 1, 2, -1, -4]
满足要求的三元组集合为: [ [-1, 0, 1], [-1, -1, 2] ]
代码如下:
点击查看代码
#include"../tools.h"
#include<unordered_map>
vector<vector<int>> findThreeSum(vector<int>& nums)
{
vector<vector<int>> ans;
// 排序
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); ++i)
{
// 无负数大于 0
if (nums[i] > 0)
return ans;
// 前者去重
if (i > 0 && nums[i] == nums[i - 1])
continue;
// 双指针
int left = i + 1;
int right = nums.size() - 1;
while (right > left)
{
if (nums[i] + nums[left] + nums[right] > 0) --right;
else if (nums[i] + nums[left] + nums[right] < 0) ++left;
else
{
ans.emplace_back(vector<int>({nums[i], nums[left], nums[right]}));
// 导入后,后两者去重
while (right > left && nums[right] == nums[right - 1]) --right;
while (right > left && nums[left] == nums[left + 1]) ++left;
// 对准不重复的
--right;
++left;
}
}
}
return ans;
}
int main()
{
vector<int> nums = {-1, 0, 1, 2, -1, -4};
showArr2D(findThreeSum(nums));
return 0;
}
8. 四数之和
给定一个包含 n 个整数的数组 nums 和一个目标值 target,
判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?
找出所有满足条件且不重复的四元组
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2], target = 0
满足要求的三元组集合为: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]
代码如下:
点击查看代码
#include"../tools.h"
#include<unordered_map>
vector<vector<int>> findFourSum(vector<int>& nums, int target)
{
vector<vector<int>> ans;
// 排序
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); ++i)
{
// 正数提前剪枝
if (nums[i] > target && nums[i] >= 0)
break;
// 前者去重
if (i > 0 && nums[i] == nums[i - 1])
continue;
for (int j = i + 1; j < nums.size(); ++j)
{
if (nums[i] + nums[j] > target && nums[i] + nums[j] >= 0)
break;
if (j > i + 1 && nums[j] == nums[j - 1])
continue;
// 双指针
int left = j + 1;
int right = nums.size() - 1;
while (right > left)
{
if ((long)nums[i] + nums[j] + nums[left] + nums[right] > target) --right;
else if ((long)nums[i] + nums[j] + nums[left] + nums[right] < target) ++left;
else
{
ans.emplace_back(vector<int>({nums[i], nums[j], nums[left], nums[right]}));
// 导入后,后两者去重
while (right > left && nums[right] == nums[right - 1]) --right;
while (right > left && nums[left] == nums[left + 1]) ++left;
// 对准不重复的
--right;
++left;
}
}
}
}
return ans;
}
int main()
{
vector<int> nums = {1, 0, -1, 0, -2, 2};
int target = 0;
showArr2D(findFourSum(nums, target));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本