提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
1.当出现需要快速查找一个数是否曾经出现过,就需要用到哈希表。
一、有效的字母异位词(力扣242)
实现思想:当需要执行查找操作的时候,可以使用到哈希表进行操作,将第一个字符串的每一个字母存储进哈希表,然后遍历第二个字符串的每一个字母,看是否在哈希表中是否出现过,以及出现了几个,这样就可以对比两个字符串是不是字母异或
1.力扣实现
class Solution {
public:
bool isAnagram(string s, string t) {
int record[26] = {0};
for (int i = 0; i < s.size(); i++){
record[s[i] - 'a']++;
}
for(int i = 0; i < t.size(); i++){
record[t[i] - 'a']--;
}
for (int i = 0; i < 26; i++){
if (record[i] != 0) return false;
}
return true;
}
};
2.自行实现
#include <iostream>
using namespace std;
bool function(string s, string t){
//初始化方式
int record[26] = {0};
for (int i = 0; i < s.size(); i++){
record[s[i]-'a']++;
}
for (int i = 0; i < t.size(); i++){
record[t[i]-'a']--;
}
for (int i = 0; i < 26; i++){
if (record[i] != 0) return false;
}
return true;
}
int main(void){
string s, t;
cin >> s >> t;
cout << function(s, t);
return 0;
}
二、赎金信(力扣383)
实现思想:这道题和上一道题类似,但有一点不同,这道题相当于是判断字符串1是不是字符串2的子集,也就是说字符串2可能存在多余的字母,如果依旧按照上一题的方法做,会出错误。判断过程:如果字符串1长度 > 字符串2长度,则直接返回false,否则就先将字符串2存储进哈希表使每个元素+=1,然后遍历字符串1 使每个元素 -= 1,最后如果哈希表中的元素均 > 0,就说明字符串1是字符串2的子集
1.力扣实现
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26] = {0};
if (ransomNote.size() > magazine.size()){
return false;
}
for (int i = 0; i < magazine.size(); i++){
record[magazine[i] - 'a']++;
}
for (int i = 0; i < ransomNote.size(); i++){
record[ransomNote[i] - 'a']--;
}
for (int i = 0; i < 26; i++){
if (record[i] < 0) return false;
}
return true;
}
};
三、两个数组的交集(力扣349)
实现思想:这道题目要用到unordered_set,这个哈希表内部是不可以重复的,也就符合这道题的要求当一个数字多次出现的时候,只保存一遍。先将第一个数组中的元素映射到哈希表中,再遍历第二个数组中的元素是否在哈希表中出现过
1.力扣写法
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result;
unordered_set<int> map(nums1.begin(), nums1.end());
for (auto p: nums2){
if (map.find(p) != map.end()){
result.insert(p);
}
}
return vector<int>(result.begin(), result.end());
}
};
2.自行实现
#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;
vector<int> function(vector<int> &nums1, vector<int> &nums2){
unordered_set<int> result_set;
//迭代器构造unordered_set容器,将nums1中的数字填入nums_set中
unordered_set<int> nums_set(nums1.begin(), nums1.end());
for(auto p : nums2){
//针对find函数的查找标准
//如果find函数没有找到就会返回nums_set的end
//也就是说如果返回的值不是nums_set的end就说明找到了值
if(nums_set.find(p) != nums_set.end()){
result_set.insert(p);
}
}
//返回一个匿名的容器,没有重新命名,相当于临时性的容器
return vector<int>(result_set.begin(), result_set.end());
}
int main(void){
vector<int> nums1 = {1, 2, 2, 1};
vector<int> nums2 = {2, 2};
vector<int> result = function(nums1, nums2);
for (auto p : result){
cout << p << ' ';
}
return 0;
}
四、两个数组的交集ll(力扣350)
实现思想:这道题目同上面不同,上面的是返回的交集是即便一个数字出现了多次也只返回一个举例:nums1 = [1,2,2,1],nums2 = [2,2] 上面的题目返回的是[2],而这道题目需要返回[2, 2],也就是说有几个重复的数字就返回几个,我们要记录它出现的次数,这个时候unordered_set就不适用了因为它只能查看这个值是否出现过,而不能看出现了几次。因此在这道题中我们要用到unordered_map,unordered_map需要初始化两个变量属性
1.力扣写法
class Solution {
public:
vector<int> intersect(vector<int>& nums1, vector<int>& nums2) {
vector<int> result;
unordered_map<int,int> map;
for (auto p: nums1){
map[p]++;
}
for (int i = 0; i < nums2.size(); i++){
if (map[nums2[i]]-- > 0){
result.push_back(nums2[i]);
}
}
return result;
}
};
2.自行实现
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
void function(vector<int> &nums1, vector<int> &nums2){
vector<int> result;
unordered_map<int, int> nums;
for (auto p: nums1){
nums[p]++;
}
for (int i = 0; i< nums2.size(); i++){
if (nums[nums2[i]]-- > 0){
result.push_back(nums2[i]);
}
}
for (auto p: result){
cout << p << ' ';
}
}
int main(void){
vector<int> nums1 = {4,7,9,7,6,7};
vector<int> nums2 = {5,0,0,6,1,6,2,2,4};
function(nums1, nums2);
return 0;
}
五、快乐数(力扣202)
实现思想:这里首先要学习一下如何取得一个数字n每一位上的数字,让n%10我们可以取得n个位上的数字,在让n = n/10就让高位的数字向低位移动一位,如此反复循环就可以取得每一位上的数字。其次,由题目可知这道题目可能发生无限循环,因此需要两个判断条件,一个判断什么时候返回true,由题目可知如果sum=1就返回,另一个判断什么时候返回false,如果这个初始数字不是快乐数,那么他就会陷入一个循环,因此如果在循环中发现sum在先后出现了同一个数字,那么就说明这个数字不是快乐数返回false。
1.力扣实现
class Solution {
public:
int get_sum(int n){
int sum = 0;
while(n){
sum += (n%10)*(n%10);
n = n/10;
}
return sum;
}
bool isHappy(int n) {
set<int> map;
while(1){
int sum = get_sum(n);
if (sum == 1) return true;
else{
if (map.find(sum) != map.end()) return false;
else{
map.insert(sum);
}
}
n = sum;
}
}
};
六、两数之和(力扣1)
实现思想:这道题目要用到unordered_map结构,因为我们既需要保存数字本身,还需要保存它的下标,循环数组每次寻找能和当前数字凑成target的数字,如果找到就直接返回当前数字和其满足要求的数字的下标,如果没有找到就将数字及其下标添加到unordered_map中,如果循环完一整个数组还没有找到就返回空。(注意这道题返回的结构)
1.力扣实现
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 iter = map.find(target-nums[i]);
if(iter != map.end()){
return {iter->second, i};
}else{
map.insert(pair<int,int>(nums[i], i));
}
}
return {};
}
};