1.基础知识——哈希表
当需要判断一个元素是否出现在一个集合里的时候考虑用哈希表。
哈希表:哈希表是根据关键码的值而直接进行访问的数据结构。
哈希函数:映射关系,映射到索引下标
哈希碰撞:拉链法,线性探测法
实现哈希表的数据结构:数组,set,map;数组用于数值范围小可用数组下标映射实际数值。set可用于大数值范围,或者数值范围小但是数值差距大(使用数组会造成内存空间浪费例如0,1,9999)。需要使用 key value结构来存放时,key来存元素,value来存下标,那么使用map。
2.有效的字母异位词
题意理解:
判断两个字符串是否由相同数目的相同字母组成,构成字符串的字符由26个小写字母组成。
解法:
数组就是一个简单的哈希表。构建一个长度为26的数组,数组下标0~25分别对应小写字母a~z。数组初始化全赋值为0,通过对字符串s的遍历,对s中出现的字母在数组相应下标的值进行+1操作,接着对第二个字符串t遍历,对t中出现的字母在上述同一数组相应下标的值进行-1操作,最后通过判断数组每个元素是否都为0,来判断两个字符串是否出现相同字母且相同字母出现的次数是否也相同,即是否两个字符串互为有效的字母异位词。
LeetCode242代码实现
class Solution {
public:
bool isAnagram(string s, string t) {
int hash[26] = {0};
int i;
for(i=0;i<s.size();i++){
hash[s[i]-'a']++;
//因为字符a到字符z的ASCII是26个连续的数值,所以字符a映射为下标0,相应的字符z映射为下标25。
}
for(i=0;i<t.size();i++){
hash[t[i]-'a']--;
}
for(i=0;i<26;i++){
//hash数组如果有的元素不为零0,说明字符串s和t,一定是谁多了字符或者谁少了字符。
if(hash[i]!=0) return false;
}
return true;
}
};
3. 两个数组的交集
题意理解:
给了两个数组,求两个数组中都出现的元素,不考虑输出顺序但是输出的结果元素唯一,去除重复数字。
解法:
将nums1放入哈希表nums_set中,然后遍历nums2,在哈希表nums_set中查是否出现过,若出现过即为两个数组重复出现的数值,如果出现过,再将这个数放入result集合中。result的数据结构为unordered_set,可以实现去重操作;哈希表也使用unordered_set。
LeetCode349代码实现
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result_set; // result集合用于存放结果,之所以使用unordered_set是为了给结果集去重
unordered_set<int> nums_set(nums1.begin(), nums1.end());//将数组nums1用unordered_set存放为nums_set,用于哈希查值并且实现去重
for (int num : nums2) {//遍历数组nums2
if (nums_set.find(num) != nums_set.end()) {//检查nums2的元素是否在nums_set里出现
result_set.insert(num);//如果找到交集元素,把它放入result_set里
}
}
return vector<int>(result_set.begin(), result_set.end());//;unordered_set转换为vector数组
}
};
4.快乐数
解题思路:
按照题意理解什么是【快乐数】,其中题目中的关键信息为:可能出现无限循环而变不到1。对无限循环的理解:在求和过程中,sum会重复出现,从而陷入无限循环中。当需要快速判断一个元素是否在某一个集合中时,考虑哈希法。
使用哈希法判断sum是否重复出现,如果重复出现了就return FALSE,否则一直找到sum为1。判断sum是否重复出现使用unordered_set。
LeetCode202代码实现
class Solution {
public:
int getSUM(int n){//函数getSUM获得数n各个位上数字平方之和
int sum = 0;
while(n){//得到数n各个位上数字平方之和
sum += (n%10)*(n%10);//模运算获得数字的个位
n /= 10;//整除10将数字除去个位
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> set;
while(1){
int sum = getSUM(n);
if(sum == 1){
return true;
}
//当sum在集合set中重复出现,return FALSE
if(set.find(sum) != set.end()){
return false;
}else{//若sum不为1,将sum放入unordered_set集合set中
set.insert(sum);
}
n = sum;
}
}
};
5. 两数之和——第一题解不出来是正常的吧?肯定是的,对,一定是的
解题思路:
寻找数组中两数之和为target的元素下标,可以转换为遍历数组nums,在集合map中寻找 target-nums[i] 这个数是否在数组中出现过,例如数组{2,6,5,7},target=9;遍历数组,遍历2时查找map中是否有7,没有把key=2,value=0(数组下标)放入map中,接下来,遍历6时查找map中是否有3,没有把key=6,value=1(数组下标)放入map中,接下来,遍历5时查找map中是否有2,有则把key=2的value=0和数组元素5的下标2,{0,2}一起返回得到答案。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map <int,int> map;
for(int i = 0; i < nums.size(); i++) {
// 遍历数组当前元素,并在map中寻找是否有匹配的key
auto iter = map.find(target - nums[i]);
if(iter != map.end()) {
return {iter->second, i};
}
// 如果没找到匹配对,就把访问过的元素和下标加入到map中
map.insert(pair<int, int>(nums[i], i));
}
return {};
}
};
总结:
2023年4月10日22:18:15
任务未完成,明天继续。
2023年4月14日22:29:11
缺乏C++语法知识学习,应尽快学习,弥补知识短板,否则代码不会写,也看不懂
时隔5天才将这一任务完成。时间安排规划!!!