454.四数相加II
常规思路为四个for循环嵌套,复杂度过高O(n^4);我分别用了两个哈希表,统计了两个数之和的出现次数;,结果再相乘。举例a数组元素+b数组元素 = 3,出现了2次;c数组元素+d数组元素 = -3,出现了4次;那么总的结果就是 2 * 4 = 8。PS:写入哈希表可以umap[n],读取哈希表为umap.at(n) 而不是 umap[n]。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int> umap1;
unordered_map<int,int> umap2;
int sum = 0;
for(auto s:nums1) {
for(auto t:nums2) {
umap1[s+t]++;
}
}
for(auto s:nums3) {
for(auto t:nums4) {
umap2[s+t]++;
}
}
for(auto n:umap1) {
int tmp = n.first;
if(umap2.find(-tmp) != umap2.end()) {
sum += umap1.at(tmp) * umap2.at(-tmp);
}
}
return sum;
}
};
383. 赎金信
采用哈希表记录出现的次数,因为magazine
中的每个字符只能在 ransomNote
中使用一次,所以通过计数加减进行判断。注意判断条件:不是哈希表的值s.second != 0而是 > 0,特例为第一个数组"abcd", 第二个数组"abcdabcd",这样判断完哈希表的值为负数,一开始疏忽了这点。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int count = 0;
unordered_map<char,int> umap;
for(auto s:ransomNote) {
umap[s]++;
}
for(auto s:magazine) {
if(umap.find(s) != umap.end()){
umap[s]--;
}
}
for(auto s:umap) {
if(s.second > 0)//注意这里
return false;
}
return true;
}
};
15. 三数之和
这题做不来直接翻答案了。。。思路很简单,先排序接着使用三个指针计算和。但是要处理的条件很多,一不留神就会忽略。我看了思路然后做题,也没能考虑齐全条件,错误见注释。(这类题得review)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
std::sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); ++i) {
if(nums[i] > 0) return res;
//跳过重复的数字,不能nums[i] == nums[i+1],会跳过前两个数字相同的情况。
if(i > 0 && nums[i] == nums[i - 1]) continue;
int j = i + 1;
int k = nums.size() - 1;
while(j < k) {
if(nums[i] + nums[j] > 0) return res;
if(nums[i] + nums[j] + nums[k] > 0)
k--;
else if(nums[i] + nums[j] + nums[k] < 0)
j++;
else {
res.push_back({nums[i],nums[j],nums[k]});
//因为使用了两个指针表示后面两个数字,所以前瞻性地使用nums[k]=nums[k-1]
//换句话说即使用k忽略了两个相同的数字,nums[j]也能表示这个被忽略的数字
//当然这么写也完全没问题,k < nums.size() - 1 && nums[k] == nums[k + 1]
while(j < k && nums[k] == nums[k - 1])
k--;
while(j < k && nums[j] == nums[j + 1])
j++;
j++;
k--;
}
}
}
return res;
}
};
18. 四数之和
除了双指针法想不到别的方法了,看了答案也只有这个办法。总结一下:
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int h = 0; h < nums.size(); ++h) {
long long x = nums[h];
//这里有负数的可能不能 x > target,比如说{-3,-2,-1},target = -5;
// if(x > target && x >= 0) return res;
if(h > 0 && nums[h] == nums[h - 1])
continue;
for(int i = h + 1; i < nums.size(); ++i) {
long long y = nums[i];
// if(x + y > target && x + y >= 0) return res;
if(i > h + 1 && nums[i] == nums[i - 1])
continue;
int j = i + 1;
int k = nums.size() - 1;
while(j < k) {
if((long)nums[h] + nums[i] + nums[j] + nums[k] > target)
k--;
else if((long)nums[h] + nums[i] + nums[j] + nums[k] < target)
j++;
else
{
res.push_back({nums[h],nums[i],nums[j],nums[k]});
while(j < k && nums[k] == nums[k - 1])
k--;
while(j < k && nums[j] == nums[j + 1])
j++;
k--;
j++;
}
}
}
}
return res;
}
};
1. 这类题去重要慎重,不能漏掉重复的数字。
2. 这儿要返回具体的数,但是哈希表只能反映次数和总和,所以不能用。
3. 双指针法能处理的也只有两个数字,数字变多后还是得放入循环中解决。