1.哈希表
哈希表是用于快速查找目标的数据结构,有三种:数组、集合和映射。
数组是以下标为索引的哈希结构,通过下标能直接访问对应元素,查找时间复杂度为O(1)。数组数据的最大长度是1000。所以遇到固定长度,数据跨度小的问题可以使用数组解决。
集合在C++中有三种:
根据题目需要使用顺序为unordered_set -> set -> multiset。集合的操作有:find、insert、erase等
映射同样有三种:
根据题目需要使用顺序为unordered_map -> map -> multimap。map存储键值对,可以通过key找到对应value。
2.字母异位
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
视频讲解:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词_哔哩哔哩_bilibili
本体考察两个字符串出现的字母及其数量是否完全相同。所以我们自然想到是否可以统计每一个字母的数量,再将二者对比。而提到查找某个元素是否出现的时候,要立刻想到哈希法。
本体使用哪种哈希结构呢,我们需要统计字母及其数量,所以排除set。再看能不能使用数组,字母一共26个,个数确定,所以可以使用数组表示。26个字母分别代表0-25的数组下标,数组元素表示其出现次数。
我们需要两个数组来对比其是否完全相同,但是还有个方法是第二个字符串的统计可以在同一个数组中做减法。如果最后数组元素全为0,即证明两个字符串是异位的。
代码如下:
bool isAnagram(string s, string t) {
vector<int> count(26,0);
for (int i = 0; i < s.length(); ++i) {
count[s[i] - 'a']++;
}
for (int i = 0; i < t.length(); ++i) {
count[t[i] - 'a']--;
}
for (int i = 0; i < 26; ++i) {
if (count[i] != 0)
return false;
}
return true;
}
tips:如何用下标表示26个字母?a用0表示,因为小写字母在ASCII码上是连续的,后面的字母与a相差多少位,其下标就是多少。所以其他字母的下标是x(任意字母)- 'a'。
2.数组交集
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
视频讲解:学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集_哔哩哔哩_bilibili
本体最后的结果数组中元素是唯一的,所以我们要判断有没有在两个数组中都出现过的元素。判断元素是否存在立即想到哈希法。
再考虑使用哪种数据结构。本体并不需要返回元素的位置,只需要找到元素即可,所以使用set。且结果数组元素不重复且无序,使用unordered_set。
本体准备两个set。第一个set记录数组1的元素(自动去重),再循环中每次判断数组2的元素是否出现在set1中。如果出现,将它记录到set2中。最后将set2内容转化为数组即可。
代码如下:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
//结果集合
unordered_set<int> result_set;
//记录集合,将nums1记录到集合中
unordered_set<int> record_set(nums1.begin(), nums1.end());
//将nums2中的每一个元素放到临时变量num中
for (int num : nums2){
//unordered_set.find()函数找到目标时会返回指向目标元素的迭代器,
//否则返回unordered_set.end,表示集合的末尾
if (record_set.find(num) != record_set.end())
//集合插入元素
result_set.insert(num);
}
//创建以结果集合内容初始化的容器
return vector<int>(result_set.begin(),result_set.end());
}
tips:本体涉及一些第一次接触的语法内容,如set的初始化(使用数组),数组的初始化(使用set),判断set是否找到内容,set插入新元素以及for循环的新写法等。
3.快乐数
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
本体最重要的是搞清楚判断逻辑:是快乐数的话改数最后运算会变成1,如果不是的话会陷入循环。所以我们要知道运算过程中该数是否重复出现,因此使用哈希法。
数据结构依然使用set,因为只需要判断是否存在。
此外每个数运算过程建议写成函数方便调用。
代码如下:
int getSum(int num){
int sum = 0;
while (num){
sum += (num % 10) * (num % 10);
num /= 10;
}
return sum;
}
bool isHappy(int n) {
unordered_set<int> record_set;
while (1){
if (getSum(n) == 1)
return true;
else{
n = getSum(n);
if (record_set.find(n) != record_set.end())
return false;
record_set.insert(n);
}
}
}
4.两数之和
题目链接:. - 力扣(LeetCode)
讲解链接:代码随想录 (programmercarl.com)
视频讲解:梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!_哔哩哔哩_bilibili
本题判断一个数组中是否存在和为目标值的两个元素,并返回他们的下标。目标是查找,所以使用哈希法。
再判断使用什么数据结构,本体不但需要查找元素,还要返回下标。所以不能使用set。另外数组内元素范围不知道,所以不方便使用数组。因此本体使用map。考虑到结果集无序且不重复,使用unordered_map。
遍历数组,每次在map中查找是否存在与当前元素和为目标值的元素,是则返回下标(循环中的i与map中key对应的value),否则记录元素及其下标分别为key-value。
代码如下:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> record_map;
for (int i = 0 ; i < nums.size() ; i++) {
auto iter = record_map.find(target - nums[i]);
if (iter != record_map.end())
return {iter->second, i};
record_map.insert(pair<int, int>(nums[i], i));
}
return {};
}
tips:本体涉及map相关语法,包括初始化与插入键值对的语法。另外包含c++迭代器的内容。