前言
今日文案:
盐于律己,甜以待人
一、有效的字母异位词
题目描述:
给定两个字符串 s 和 t ,编写一个函数来判断 t 是否是 s 的字母异位词。
注意:若 s 和 t 中每个字符出现的次数都相同,则称 s 和 t 互为字母异位词。
题目来源:
解题思路:
本题主要是用的哈希结构是——数组。因为我们可以看到,我们的对象只是26个字母,长度比较小,所以我们可以创作数组结构来实现,如果很大的话我们会浪费很多空间。
数组的哈希结构,主要是我们创建一个哈希数组(就是普通数组,我们叫哈希数组是为了区分而已),然后去把目标数组遍历,把目标数组的值 通过处理,然后变成数组的下标,对应下标的哈希数组++,这样我们就可以通过比对找出我们想要的结果。
代码如下:
bool isAnagram(char * s, char * t){ int arr[26]={0},a=1; for(int i=0;i<strlen(s);i++) //遍历数组 { arr[s[i]-'a']++; //利用阿斯卡码值,得出对应下标++ } for(int i=0;i<strlen(t);i++) { arr[t[i]-'a']--; //这里注意是减减(外边有说明) } for(int i=0;i<26;i++) //如果你最后的数组都是0,说明字母出现次数是一样的 { if(arr[i]!=0) a=0; } if(a==0) return false; else return true; }
关于那个- -的地方,也是我踩的一个坑,我最初的想法是,我都是++,然后数组里面出现的不是2就是0,不久可以认为两个字符串是一对一对出现的吗,这样不久等于消消乐一样,简简单单吗。
但是消消乐会消,我这里没有写啊,鬼知道一个字符串里面相同的字母会出现多少次次呢,因此我们通过- -来判断,==0就说明他们两个相互抵消辣~
二、两个数组的交集
问题来源:
1.数组解法(c)
上面我们学习了数组解法,我这题也尝试着使用了一下。因为要求两个数组的交集,那我们只要使用哈希数组,把数组出现的元素都保存好,然后用两个哈希数组一比对就知道是不是同时出现了。
代码如下:
int* intersection(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ int *p=(int *) malloc(sizeof(int)*1000); //申请空间作为存放答案的地方 int arr[1001]={0},brr[1001]={0},j=0; //定义两个数组,作为哈希数组 for(int i=0;i<nums1Size;i++) { arr[nums1[i]]++; //做第一个数组的哈希表 } for(int i=0;i<nums2Size;i++) { brr[nums2[i]]++; //第二个数组的哈希表 } for(int i=0;i<1000;i++) { if(arr[i]>0&&brr[i]>0) //比对两个哈希数组,同时大于0,是明是交集 { p[j]=i; //保存好 j++; } } *returnSize=j; //返回 return p; }
上面那种方法比较简单易懂,但是low,肯定有小伙伴不满足于此,下面我来解释另外一种哈希结构——set.
2、set解法(c++)
按我的理解(初学):unordered_set<int> 这种结构,它是可以自动帮你筛除去重复的元素,也就是说,储存的元素都是不重复的,而且空间是比较有弹性的,不需要像数组一样一次定义,可能会造成浪费。
代码如下:
class Solution { public: vector<int> intersection(vector<int>& nums1, vector<int>& nums2) { unordered_set<int> ans; int has[1000]={0},a=0; for(int i=0;i<nums1.size();i++) //把目标数组1的值作为下标对应哈希数组置1 { has[nums1[i]]=1; } for(int i=0;i<nums2.size();i++) //用目标数组2的值作为下标索引 { if(has[nums2[i]]==1) //如果也等于1,那么说明是相交的 { ans.insert(nums2[i]); //这里是插入相交的值,因为set,是不会插入重复的值的 a++; } } return vector<int>(ans.begin(), ans.end()); //返回 } };
三、快乐数
题目来源:
思路:
1、首先我们可以看见,这个快乐数好像和我们的水仙花数有点类似,都是用每一位的和的平分加起来。但不一样的是,水仙花数只需要一次就可以判断了,但这个好像需要很多次,而且有可能进入死循环。
2、我们怎么判断死循环呢,当一个结果在里面重复出现了,我们就可以判断是死循环了,是一辈子得不到那个1的。
代码如下(示例):
int f(int n) //计算函数 { int sum=0; while(n) { sum=(n%10)*(n%10)+sum; //拆数 n=n/10; } return sum; } class Solution { public: bool isHappy(int n) { unordered_set<int> p; //一个set结构 while(1) { int sum=f(n); //每次计算一次 if(sum==1) return true; if(p.find(sum)!=p.end()) //因为find如果找不到那个值,它会=p.end() return false; else{ p.insert(sum); //如果没有找到1,也还没有判断进入死循环,把当前的sum插 } 入set里面,以后可以判断是否出现死循环 n=sum; //新的一轮起始数 } } };
四、两数之和
力扣第一题,真就,有人夜里开车看海,有人谈情说爱,有人力扣第一道题都写不出来呗。
题目来源:
思路:
1、暴力破解,没什么技术难度,两个for搞定。
2、用map。
代码如下:
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { unordered_map<int,int> map; for(int i=0;i<nums.size();i++) { int w=target-nums[i]; auto adr=map.find(w); if(adr!=map.end()) return {adr->second,i}; else map.insert(pair<int,int>(nums[i],i)); } return {}; } };
关于map,我也没有了解得很明白,下面是我一点粗浅的理解:
map里面有两个数据类型,一个存地址一个存值,我们在这里只需要两步
1、搜索以前有没有出现这个值
2、存储出现的值
下面是四个需要思考的问题:
1、为什么想到用哈希法。
2、我们为什么要用map。
3、map究竟是用来干什么的。
4、map里面的key是用来存什么的。
ps :图书馆要关门了,交给你们了hhh
总结
今天是算法训练的第六天,新学了很多c++的东西,我也准备使用c++刷题了,加油加油!!!