看到这题很多人应该都想到了我们的两数之和吧,这个题的哈希做法其实就是两数之和的ProMax版:在两数之和中,我们一边把当前遍历的数放入哈希表一边在哈希表中查找是否存在满足target-nums[i]的值;而在这个四数之和中,我们就可以把前两个数组的数分别循环求和后认作第一个放进哈希表的数,再在哈希表中查找是否存在后续的两个数组的循环求和后得到的满足target-nums[a]-nums[b]的数即可。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
int res=0,n=nums1.size();
unordered_map<int,int> mp;
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
mp[nums1[i]+nums2[j]]++;
}
}
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
if(mp.contains(-nums3[i]-nums4[j])){
res+=mp[-nums3[i]-nums4[j]];
}
}
}
return res;
}
};
这个题我们最推荐的方法就是用数组作为哈希表记录所有出现的字母,还记得我说过的吗:数组就是最简单的哈希表。我们只要发现数组中存在另一个字符串中不存在的字符就可以返回false,不然就返回true就好了。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26]={0};
for(int i=0;i<magazine.size();i++){
record[magazine[i]-'a']++;
}
for(int i=0;i<ransomNote.size();i++){
record[ransomNote[i]-'a']--;
if(record[ransomNote[i]-'a']<0)return false;
}
return true;
}
};
这个题,说实话我没想到会被归类到哈希表中,事实上我根本就不知道这个题的哈希表做法是什么。在我看来这就是一个纯粹的双指针的题,而且包含着去重的步骤。我们要在每次更新这三个数的序号的时候进行去重的过程。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
for(int i=0;i<nums.size();++i){
if(i>0&&nums[i]==nums[i-1])continue;
int j=i+1,k=nums.size()-1;
while(j<k){
int sum=nums[i]+nums[j]+nums[k];
if(sum==0){
res.push_back({nums[i],nums[j],nums[k]});
++j;
--k;
while(j<k && j>i+1 && nums[j]==nums[j-1]) ++j;
while(j<k && k<nums.size()-1 && nums[k]==nums[k+1]) --k;
}
else if(sum>0){
--k;
}
else ++j;
}
}
return res;
}
};
这里我们发现sum==0后需要进行的操作就是先更新一遍序号,再进行查重,避免重复查重。
其实本质上和三数之和是一个题目,外面多套一层循环罢了,不过这个题不知道谁搞了个long long的测试样例,搞得人不人鬼不鬼的,所以我们需要进行一些类型转换才能通过。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
for (int a = 0; a < nums.size(); ++a) {
if (a > 0 && nums[a] == nums[a-1]) continue;
for (int b = a + 1; b < nums.size(); ++b) {
if (b > a + 1 && nums[b] == nums[b-1]) continue;
int c = b + 1, d = nums.size() - 1;
while (c < d) {
long long sum = static_cast<long long>(nums[a]) + nums[b] + nums[c] + nums[d];
if (sum == target) {
res.push_back({nums[a], nums[b], nums[c], nums[d]});
++c;
--d;
while (c < d && nums[c] == nums[c-1]) ++c;
while (c < d && nums[d] == nums[d+1]) --d;
}
else if (sum > target) --d;
else ++c;
}
}
}
return res;
}
};
然后我又多做了一些额外的题目,总的来说没有很难。
字母异位词类的题目总体来说都差不多,利用sort进行排序后就能得到相同的字符了。
class Solution {
public:
vector<vector<string>> groupAnagrams(vector<string>& strs) {
vector<vector<string>> res;
unordered_map<string,vector<string>> mp;
for(string str:strs){
string tem=str;
sort(tem.begin(), tem.end());
mp[tem].push_back(str);
}
for(auto it=mp.begin();it!=mp.end();++it){
res.push_back(it->second);
}
return res;
}
};
不过要是不允许用sort怎么办?这还真是个问题。
438. 找到字符串中所有字母异位词 - 力扣(LeetCode)
这个题需要我们用数组去记录需要找的字符串的各字符出现次数,然后再用一个双指针实现滑动窗口的效果,如果滑动窗口的长度与我们的字符串长度相等则满足条件,我们返回左指针即可。
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> res;
int temp[26];
for(int i=0;i<p.size();++i){
temp[p[i]-'a']++;
}
for(int r=0,l=0;r<s.size();++r){
temp[s[r]-'a']--;
while(temp[s[r]-'a']<0){
temp[s[l]-'a']++;
++l;
}
if(r-l+1==p.size())res.push_back(l);
}
return res;
}
};
这样哈希表的内容我们也完成了,哈希表主要的任务就是查重,包含数组,set,map三种形式,数组自带键(数组下标),set自带去重功能,而map能灵活实现建立映射的效果,在不同的题之间需要灵活使用。

911

被折叠的 条评论
为什么被折叠?



