目录
哈希表的适用场景:元素在集合中是否出现过
本人不可能用C写哈希的!
242.有效的字母异位词
题目链接:力扣
题目描述:给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
示例:输入: s = "anagram", t = "nagaram"
输出: true
输入: s = "rat", t = "car"
输出: false
字符串中字母均为小写,将26个小写字母与数组下标做对应,用数组实现哈希表。
不必开辟两个数组来分别记录两个字符串中各个字母出现的次数。单个数组记录一个字符串中字母出现次数,另一个字符串出现字母数在此数组上做减法,最后判根据组中个元素是否为零来判断出现次数是否相等。
bool isAnagram(char * s, char * t){
int box[26]={0};
//s串对数组做加法
while(*s!='\0'){
box[(*s++)-'a']++;
}
//t串对数组做减法
while(*t!='\0'){
box[(*t++)-'a']--;
}
//判断各元素是否为0
for(int i=0;i<26;i++){
if(box[i]!=0)
return false;
}
return true;
}
349. 两个数组的交集
题目链接:力扣
题目描述:给定两个数组
nums1
和nums2
,返回 它们的交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例:输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
1.数组实现
类似于上面242.有效的字母异位词。
注意:结果是去重的,因此在每次在结果数组中加入一个元素要相应的将对应临时数组中元素值置为其他值,我置为0了,防止结果出现重复值。如果没有此操作,像示例1返回的结果就是[2,2]。
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){
int temp[1001]={0};
int *ret=(int *)malloc(sizeof(int)*fmin(nums1Size,nums2Size));
*returnSize=0;
//将nums1中出现的元素对应的数组元素置1
for(int i=0;i<nums1Size;i++){
temp[nums1[i]]=1;
}
//也在nums2中出现的元素添加到返回结果数组
for(int i=0;i<nums2Size;i++){
if(temp[nums2[i]]==1){
ret[(*returnSize)++]=nums2[i];
//结果集去重,置0防止再一次出现被放入结果数组
temp[nums2[i]]=0;
}
}
return ret;
}
2.C++ unordered_set
不会C++!考研C程序设计大概率数值不会那么大,用数组可以解决;面试肯定也不会想看我用C实现哈希吧!有更好的办法,有时间我会学cpp的。
尽可能把代码替换成了能看懂的C!
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//定义结果集
unordered_set<int> result_set;
//存放nums1中出现的值
unordered_set<int> nums_set(nums1.begin(),nums1.end());
for(int i=0;i<nums2.size();i++){
//如果nums2中的元素在nums_set中出现过将元素插入结果集
if(nums_set.find(nums2[i])!=nums_set.end()){
result_set.insert(nums2[i]);
}
}
return vector<int>(result_set.begin(),result_set.end());
}
};
202. 快乐数
题目链接:力扣
题目描述:
编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
示例:
输入:n = 19
输出:true
解释:
1.递归+试
确定结束条件:很显然当数在[1,10)之间,为1时一定是快乐数,但为7时是快乐数,是我根据测试用例试的,计算之后发现是的。
递归:当当前各个位数的平方和>10时,进行下一轮递归
//计算当前值的各位数的平方和
int result(int n){
int sum=0;
while(n>0){
sum+=(n%10)*(n%10);
n/=10;
}
return sum;
}
bool isHappy(int n){
int temp=result(n);
//各位数的平方和小于10时,只有等于1和7时才是快乐数
if(temp==1||temp==7)
return true;
if(temp<10)
return false;
return isHappy(temp);
}
2. C++ unordered_set
根据题意,变到1的情况是快乐数可以直接true,其他情况会陷入无限循环,在不断循环的过程中,各位数的平方和一定会有重复。因此,当此次平方和与之前的重复,那么直接return false。
就两种结果:1. 循环往复,平方和等于1---->return true
2. 循环过程中出现了重复的平方和----->return false
用unordered_set判断平方和是否之前出现过。
对于unordered_set这里用到的基本操作,我根据上个题目可以写出来。要注意的是isHappy函数中的循环,由于是无限循环,while(true)或者while(1)也行,最后要更新所判断的值,也就是n=sum的语句。
class Solution {
public:
//计算各位数平方和
int result(int n){
int sum=0;
while(n>0){
sum+=(n%10)*(n%10);
n/=10;
}
return sum;
}
bool isHappy(int n) {
//创建set
unordered_set<int> sum_set;
while(true){
int sum=result(n);
//平方和是1直接返回
if(sum==1) return true;
//这个表示的是在set中出现过,出现过返回false
if(sum_set.find(sum)!=sum_set.end()){
return false;
}else{
//没出现过加到set里
sum_set.insert(sum);
}
n=sum;
}
}
};
1. 两数之和
题目链接:力扣
题目描述:给定一个整数数组
nums
和一个整数目标值target
,请你在该数组中找出 和为目标值target
的那 两个 整数,并返回它们的数组下标。你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
示例:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
1.暴力
int* twoSum(int* nums, int numsSize, int target, int* returnSize){
int i,j;
int *array=(int*)malloc(sizeof(int)*2);
*returnSize=2;
for(i=0;i<numsSize;i++){
for(j=i+1;j<numsSize;j++){
if(nums[i]+nums[j]==target){
*array=i;
*(array+1)=j;
break;
}
}
}
return array;
}
2.C++ unordered_map
假设目标和为9,出现值为3的元素时,寻找map中是否有值为6的元素。因此使用map,元素值作为key,下标作为value。
map用来存放遍历过的键值对。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
//构建map用来存放遍历过的元素
std::unordered_map<int,int> map;
for(int i=0;i<nums.size();i++){
//auto:让编译器根据赋值号右边的表达式类型推断dif的类型
auto dif=map.find(target-nums[i]);
//key=dif在map中
if(dif!=map.end()){
//返回两加数下标{dif对应的value,当前key下标}
return {dif->second,i};
}
//key=dif不在map中,插入键值对
map.insert(pair<int,int>(nums[i],i));
}
return {};
}
};
unordered_set常见操作
- unorder_set<string> first容器定义
- first.empty() 判断容器是否是空,是空返回true,反之为false
- first.size() 返回容器大小
- first.maxsize() 返回容器最大尺寸
- first.begin() 返回迭代器开始
- first.end() 返回迭代器结束
- first.find(value) 返回value在迭代器的位置
- first.count(key) 返回key在容器的个数
- first.insert(value) 将value插入到容器中
- first.erase(key) 通过key删除
- first.clear() 清空容器
unordered_map常见操作
看这个或者看书