目录
哈希表理论基础
242.有效的字母异位词
(1) 题目描述
(2) 解题思路
解题步骤:
1. 暴力解法
- 第一层for循环: 遍历s中的元素
- 第二层for循环: 遍历t中的元素,判断s中元素是否在t中出现。注意判断字母是否重复。
2. 哈希表
哈希表: 快速判断一个元素是否出现集合里。
本题目只有26个字母,数值小,范围可控 --> 数据结构使用数组
数组大小: 字符a到字符z的ascii是26个连续的数值 -->数组大小为26,初始化为0。
class solution {
public:
bool isanagram(string s, string t) {
// 哈希表法
// (1) 定义大小为26的数组作为哈希表,因为字母为26个,初始值均为0,字母a位于哈希表数组下标为0的位置。
int record[26] = {0};
// (2) 统计在s中字母的出现次数,出现一次加1
for (int i = 0; i < s.size(); i++){
// s[i]: s中第i个字符的ascii码
//'a': 字符a的ascii码(计算机内部的二进制表示)
record[s[i]-'a']++; // s[i]-'a': s中第i个字符在字母表的位置,即record中对应字符的下标位置
}
// (3) 统计在t中字母的出现次数,出现一次在哈希表中减1
for (int i = 0; i < t.size(); i++){
record[t[i]-'a']--;
}
// (4) 根据哈希表中的数值判断结果
// (4.1) record数组如果有的元素不为零0,说明字符串s和t一定是谁多了字符或者谁少了字符。
for (int i = 0; i < 26;i++){
if(record[i] != 0){
return false;
}
}
// (4.2) record数组所有元素都为零0,说明字符串s和t是字母异位词
return true;
}
};
349. 两个数组的交集
(1) 题目描述
(2) 解题思路
题目说明:输出结果中的每个元素一定是唯一的,即去重(无序)
1. 数据结构set
使用unordered_set: 读写效率是最高的,不重复,无序,且不能更改数值。
cppreference: std::unordered_set
class solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 数据结构set
// (1) 定义unordered_set存放结果,用set是给结果集去重
unordered_set<int> result_set;
// (2) 用unordered_set构造哈希表,将nums1中数据映射到哈希表
unordered_set<int> nums_set(nums1.begin(), nums1.end());
// (3) 用for循环遍历nums2中元素,检测每个元素是否是交集元素
for (int i = 0; i < nums2.size(); i++){
int num = nums2[i]; // * 上面和这行等效于 for (int num: nums2)
// (4) 检查nums2中的元素num是否在nums1映射的哈希表nums_set中出现过,如果出现,则是交集元素,将其存入结果集
// 注意: set.end() 返回的是最后的index的下一个, 即是不存在的;
// set.find(x) = set.end(): 没找到;
if (nums_set.find(num) != nums_set.end()){
result_set.insert(num);
}
}
// (5) 转换为题目要求的数据结构
return vector<int>(result_set.begin(), result_set.end());
}
};
2. 数据结构数组
使用条件: 本题后面 数值范围有限:
- 1 <= nums1.length, nums2.length <= 1000
- 0 <= nums1[i], nums2[i] <= 1000
优点: 运算速度
class solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
// 数据结构数组
// (1) 定义unordered_set存放结果,用set是给结果集去重
unordered_set<int> result_set;
// (2) 用数组构造哈希表,将nums1中数据映射到哈希表,数组大小比题目条件中的1000稍大即可,初始化均为0
int hash[1001] = {0};
// (3) 用for循环遍历nums1中元素,出现的字母在hash数组中做记录
for(int num:nums1){
hash[num] = 1;
}
// (4) 用for循环遍历nums2中元素,当nums2中元素在nums1中出现时,将其加入结果集
for (int i = 0; i < nums2.size(); i++){
int num = nums2[i]; // * 上面和这行等效于 for (int num: nums2)
if (hash[num] == 1){
result_set.insert(num);
}
}
// (5) 转换为题目要求的数据结构
return vector<int>(result_set.begin(), result_set.end());
}
};
202. 快乐数
(1) 题目描述
(2) 解题思路
基本解法思路:
- 求该数字的每一位的平方和,得到新数字
- 将新数字更新,重复上一步,直到判断结果是否为1
但难点在于该数字会陷入无限循环 --> 使用哈希表判断该数字是否出现过,出现则表示已经开始无限循环,返回false。
class solution {
public:
// 取数值各个位上的单数之和
int getsum(int n) {
int sum = 0;
while (n) { // 一直循环,直到取完n的每个位置的平方和
sum += (n % 10) * (n % 10); // n % 10: n除以10以后的余数(取余) --> 个位的数
n /= 10; // n /= 10: 相当于n=n/10,是得到n除以10的商的整数部分(取整)--> 将n去掉个位剩下的数。如19 --> 1
}
return sum;
}
bool ishappy(int n) {
// 哈希表
// (1) 定义unordered_set来判断sum是否重复出现,避免陷入无限循环
unordered_set<int> set;
// (2) 循环求数字n的每一位的平方和sum,得到后更新数字n,直到找到结果
while(1) {
int sum = getsum(n);
// (2.1) 找到最终结果为1的快乐数
if (sum == 1) {
return true;
}
// (2.2) 使用哈希表检查sum是否重复出现,当开始无限循环时
if (set.find(sum) != set.end()) { // 如果这个sum曾经出现过,说明已经陷入了无限循环了,立刻return false
return false;
} else {
set.insert(sum); // 如果这个sum没有出现过,将其加入哈希表来帮助接下来的判断
}
n = sum; // 更新数字n,直到找到结果
}
}
};
1. 两数之和
(1) 题目描述
(2) 解题思路
1. 暴力解法
class solution {
public:
vector<int> twosum(vector<int>& nums, int target) {
// 暴力解法
// (1) 定义根据题目,结果为两个下标
vector<int> result(2, 0);
// (2) 两层for循环,找到两个元素和为目标值
for (int i = 0; i < nums.size(); i++){
int sum = 0;
for (int j = i + 1; j < nums.size(); j++){ // 注意,j的初始值为i+1,因为元素不能重复
sum = nums[i] + nums[j];
if (sum == target){
result[0] = i;
result[1] = j;
break; // 题目说明,只存在一个答案,故一旦找到即可break
}
}
}
return result;
}
};
2. 哈希表map
- 为什么会想到用哈希表
- 本题需要一个集合来存放遍历过的元素,然后在遍历数组的时候去询问这个集合,某元素是否出现在这个集合 --> 哈希表
- 哈希表为何用map
- 本题不仅要知道元素有没有遍历过,还要知道这个元素对应的下标
- 代码随想录:(文字版):
- map类型
- 本题不需要key有序,选择std::unordered_map 效率更高
- map中的key和value用来存什么的
- key: 判断key是否出现 value: key对应信息
- map中的存储结构为 {key:数据元素,value:数组元素对应的下标。
class solution {
public:
vector<int> twosum(vector<int>& nums, int target) {
// 哈希表map
// (1) 定义map哈希表,kay存放元素,value存放下标
std::unordered_map<int, int> map;
// (2) 遍历nums中元素,并寻找与其和为target的另一个元素,使用哈希表查询另一个元素是否已经遍历到
for(int i = 0; i < nums.size(); i++){
// 寻找与其和为target的另一个元素
auto iter = map.find(target - nums[i]); // //find返回的是迭代器,即指针
// 使用哈希表查询另一个元素是否已经遍历到,
if (iter != map.end()){
// 当发现已经出现过,返回结果值
return {iter->second, i}; //用迭代器访问pair的first或者second成员方法是:iter->first或iter->second
}
// 当发现没有出现过,将当前元素加入map
map.insert(pair<int, int>(nums[i], i));
}
return {};
}
};
发表评论