代码随想录算法训练营第6天 | 242.有效的字母异位词 349. 两个数组的交集 202. 快乐数 1. 两数之和

哈希表理论基础

哈希表是根据关键码的值快速直接访问元素的数据结构。

  • 解决的问题:快速判断一个元素是否存在于某个集合中,如果逐个枚举的话时间复杂度为 O(n),但如果事先讲元素存在哈希表中,可以实现 O(1) 复杂度的查找。
  • 哈希函数:获取哈希表就是建立数据与哈希索引之间的对应关系。一般地,我们可以将其他数据格式通过某种编码方式转换成数字,后续可选地将这些数字转换到一个有限的值域区间来减少空间的浪费。
  • 哈希碰撞:考虑一种具体情况,如果 hashtable_size 小于原始数据的取值可能,即使哈希值分布得再均匀,也会有不同的元素映射到同一索引,也就是出现的不一一对应的映射,就发生了哈希冲突。

两种方法解决哈希碰撞:一种是拉链法,一种是线性探测法。
拉链法:将溢出元素用链表的结构存储起来,注意选取哈希表大小,既不要产生过多的空值浪费空间,也不要链表过程影响查找性能。
线性探测法:依靠哈希表中的空位来存储溢出,需要保证哈希表的大小大于原始数据的分布范围。

常见的哈希表结构

  • 数组
  • set
  • map
    在 C++ 中,以上三种是常用的哈希表结构,对于 set,有 std::setstd::multisetstd::unordered_set;对于 map,有std::mapstd::multimapstd::unordered_map

注:对与这两种结构的三种不同实现,有以下几点需要注意:

  1. 前两种实现的底层都是基于红黑树,第3种是哈希表,红黑树增删查为 O(logn),哈希表为 O(1),因此使用时优先 unordered
  2. 顾名思义,unordered的实现对于 key 没有顺序要求,但前两种都有;multi允许 key 重复值,其他两种则不允许。因此如果集合有序,就用 set,如果要允许重复 key,就用multi
  3. map只对 key 有要求,对 value 没要求,所有结构都不能修改 key。那些红黑树做底层的实现我们仍然是 key-value 这样的用法,所以也叫哈希法,C++ 中还有一些民间模板 hash_map 等,功能相同,优先用官方的吧

有效的字母异位词

Alt

思路简单,就是将字母映射到0~25作为哈希索引,数组即可解决。

class Solution{
public:
	bool isAnagram(string s, string t){
		int res[26] = {0};
		for(int i = 0; i < s.size(); i++){
			res[s[i] - 'a']++;
		}
		for(int i = 0; i < t.size(); i++){
			res[t[i] - 'a']--;
		}
		for(int i = 0; i < 26; i++){
			if(res[i]) return false;
		}
		return true;
	}
};

两个数组的交集

Alt
这道题仍然是一道数组题,可以利用双指针的方法,但前提是需要将数组进行排序,同时要注意去重复。
对于哈希方法,本题不同于上一题,上一题的哈希值分布是较小的,只需初始化一个固定大小的数组就可以实现。这道题数据范围大,哈希值可能是比较分散的,使用数组会造成比较大的空间浪费。同时题目要求输出不能重复,不需要对输出进行排序,因此选择std::unordered_set实现。

class Solution{
public:
	vector<int> intersection(vector<int>& nums1, vector<int>& nums2){
		unordered_set<int> result_set;
		unordered_set<int> num_set(nums1.begin(), nums1.end());  // 将num1转换为set,避免重复,同时进行哈希查找提升效率
		for(int num : nums2){
			if(num_set.find(num) != num_set.end()){
				result_set.insert(num);
			}
		}
		return vector<int>(result_set.begin(), result_set.end());
	}
};

注:其实如果能用数组,尽量还是用数组,因为相比之下 set 空间占用更多,将数据映射到 key 时还需要进行 hash 运算,数据规模较大时与数组相比会更慢。

快乐数

在这里插入图片描述
注意这里的无限循环很重要,说明不是快乐数时最终的 sum 会循环出现,问题判断一个数是否出现过,出现过便不是快乐数,也要注意先判断 sum == 1,不然快乐数也会在1处进入循环。

class Solution{
public:
	int getSum(int n){
		int sum = 0;
		while(n){
			sum += (n % 10) * (n % 10);
			n /= 10;
		}
		return sum;
	}
	bool isHappy(int n){
		unordered_set<int> num_set;
		while(1){
			int sum = getSum(n);
			if(sum == 1) return true;
			if(num_set.find(sum) != num_set.end()) return false;
			num_set.insert(sum);
			n = sum;
		}
	}
};

两数之和

Alt
分析:这道题需要对数值进行比对,却返回的是下标,同时数据的范围相当大。
由于 set 只是一个集合,只能存储一个个的 key,这里需要引入 key-value 这样的结构,比较的是数值,返回的是相应下标。map 正好合适,元素数值当做 key,下标做 value。由于这道题没有对顺序做要求,因此选择std::unordered_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++){
			auto it = map.find(target - nums[i]);
			if(it != map.end()) return {it->second, i};
			map.insert(pair<int, int>(nums[i], i));
		}
		return {};
	}
};
  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值