代码随想录算法训练营|哈希表内容复习
哈希表内容复习
有效的字母异位词
242. 有效的字母异位词 这个题的思路还是比较简单的,就是中间hash数组进行存储的时候不要写错了
点击查看代码
class Solution {
public:
bool isAnagram(string s, string t) {
int hash[26];
for (int i = 0; i < s.size(); i++) (hash[s[i] - 'a'])++;
for (int j = 0; j < t.size(); j++) (hash[t[j] - 'a'])--;
for (int i = 0; i < 26; i++) {
if (hash[i] != 0) return false;
}
return true;
}
};
两个数组的交集
349. 两个数组的交集 这个题有两种思路,一种使用数组做哈希表,用数组就是常见的hash[nums[i]]++这样的处理方式。还有一种思路是用set做哈希表,就是用unordered_map<int> nums做insert操作,来进行添加。特别注意这里的是insert操作,而不是数组,字符串可以用push_back,队列和栈用push
使用数组
点击查看代码
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
int hash[1001];
unordered_set<int> result;
for (int i = 0; i < nums1.size(); i++) hash[nums1[i]]++;
for (int i = 0; i < nums2.size(); i++) {
if (hash[nums2[i]] != 0) {
result.insert(nums2[i]);
}
}
return vector<int> (result.begin(), result.end());
}
};
使用set
点击查看代码
class Solution {
public:
vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
unordered_set<int> result;
unordered_set<int> nums;
for (int i = 0; i < nums1.size(); i++) {
nums.insert(nums1[i]);
}
for (int i = 0; i < nums2.size(); i++) {
if (nums.find(nums2[i]) != nums.end()) {
result.insert(nums2[i]);
}
}
return vector<int> (result.begin(), result.end());
}
};
快乐数
202. 快乐数 这个题的思路不难,关键是要想到用哈希表来进行存储,这里注意要存储的值是最后每一次计算得到的sum,刚开始犯了一个小错误,把每次查询的部分加在了分解计算的部分中。导致在用例19的最后一次计算\(1^2+0^2+0^2\)的时候会出现两次重复的1导致查询重复。
点击查看代码
class Solution {
public:
bool isHappy(int n) {
unordered_set<int> query;
while (n != 1) {
int sum = 0;
// 分解计算
while (n) {
int m = n % 10;
n = n / 10;
sum += m * m;
}
// 查询
if (query.find(sum) == query.end()) {
query.insert(sum);
} else {
// cout << sum << endl;
return false;
}
// 赋值
n = sum;
}
return true;
}
};
两数之和
1. 两数之和 两数之和还是比较简单的,就是用map结构来存储每个nums[i]和对应的索引值
点击查看代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> map;
for (int i = 0; i < nums.size(); i++) {
if (map.find(target - nums[i]) != map.end()) {
return {i, map.find(target - nums[i])->second};
}
else map.insert(pair<int, int> (nums[i], i));
}
return {};
}
};
四数相加Ⅱ
454. 四数相加 II 关于map的作用,在这里就是记录nums1和nums2中加和的个数,比如加起来是3 的有四个,加起来是4的有5个这样。这个题的核心就是用map来进行哈希表查找,最终将对应的值加起来即可
点击查看代码
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> map;
for (int i = 0; i < nums1.size(); i++) {
for (int j = 0; j < nums2.size(); j++) {
int value = nums1[i] + nums2[j];
map[value]++;
}
}
int count = 0;
for (int i = 0; i < nums3.size(); i++) {
for (int j = 0; j < nums4.size(); j++) {
int result = 0 - (nums3[i] + nums4[j]);
if (map.find(result) != map.end()) count += map.find(result)->second;
}
}
return count;
}
};
赎金信
383. 赎金信 这个题直接仿照242. 有效的字母异位词做就可以,思路也是用的那个。果然就是这样做
点击查看代码
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int hash[26];
for (int i = 0; i < magazine.size(); i++) {
hash[magazine[i] - 'a']++;
}
for (int i = 0; i < ransomNote.size(); i++) {
hash[ransomNote[i] - 'a']--;
}
for (int i = 0; i < 26; i++) {
if (hash[i] < 0) return false;
}
return true;
}
};
三数之和
15. 三数之和 这个题在开始的时候遇到对a的去重有点懵住了,为什么要对a去重呢?不是组内元素可以重复吗?
其实这么看,后面的两个left和right是和a的结果加起来为0的,如果a一直都是一个值。[a,(0-a)]后面两部分和就都是0-a,所以这样的三元组就会出现重复。
那该如何对a去重,到底是if (nums[i] == nums[i + 1])还是if (nums[i] == nums[i - 1])
其实这里但看a的话,是看不出来全貌的,要结合left看,也就是a的下一位。拿[-1,-1,2]举例。如果是if (nums[i] == nums[i + 1]),开始的时候,a=-1,这种情况continue了,下面,a=-1,第二种情况a不会跳过,此时left=2。但是我们发现了,漏掉了一种情况,就是a=-1的时候,left可以等于-1的。注意:三元组内的[a,left,right]是可以有重复的,但是三元组和三元组之间是不能有重复的
这次中间的循环写成这样的判断了,但是就是对于[-1,0,0,0,0]这种情况就无法进行去重了,result会添加好多重复的vector
for (; left < right; ) {
if (nums[i] + nums[left] + nums[right] == 0) result.push_back(vector<int> {nums[i], nums[left], nums[right]});
else {
while (nums[i] + nums[left] + nums[right] < 0) left++;
while (nums[i] + nums[left] + nums[right] > 0) right--;
}
left++;
right--;
}
正确的是
for (; left < right; ) {
if (nums[i] + nums[left] + nums[right] > 0) right--;
else if (nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back({nums[i], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
}
}
点击查看代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> result;
if (nums[0] > 0) return result;
for (int i = 0; i < nums.size(); i++) {
int a = i;
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1;
int right = nums.size() - 1;
for (; left < right; ) {
if (nums[i] + nums[left] + nums[right] > 0) right--;
else if (nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back({nums[i], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
}
}
}
return result;
}
};
四数之和
18. 四数之和 四数之和,在回顾了昨天的三树之和之后就变得简单不少,也好理解了。就是需要注意一点,在二级去重的时候,那么判断条件不要写错,if (i > k + 1 && ...)
点击查看代码
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>> result;
for (int k = 0; k < nums.size(); k++) {
// 一级剪枝
if (nums[k] > target && nums[k] > 0 && target > 0) continue;
// 一级去重
if (k > 0 && nums[k] == nums[k - 1]) continue;
for (int i = k + 1; i < nums.size(); i++) {
// 二级剪枝
if (nums[k] + nums[i] > target && nums[k] + nums[i] > 0 && target > 0) continue;
// 二级去重
if (i > k + 1 && nums[i] == nums[i - 1]) continue;
int left = i + 1;
int right = nums.size() - 1;
for (; left < right; ) {
if ((long) nums[k] + nums[i] + nums[left] + nums[right] < target) left++;
else if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) right--;
else {
result.push_back(vector<int> {nums[k], nums[i], nums[left], nums[right]});
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
}
}
}
}
return result;
}
};
做个小总结
哈希表的内容感觉写的很舒服,大致可以分成两部分内容
哈希法
从哈希表中的数组的用法242. 有效的字母异位词和赎金信,二者的思路和方法基本一致。还有set的用法349. 两个数组的交集和202. 快乐数。再到之后就是map的用法了。两数之和,四数相加都是map的典型例题
双指针法
这里的一些题目可以用双指针法来做。包括梦破碎的三数之和还有四数之和,都是用双指针来解更快更简便。
浙公网安备 33010602011771号