代码随想录算法训练营第七天 | Leetcode454.四数相加II 、Leetcode383. 赎金信、Leetcode15. 三数之和、Leetcode18. 四数之和
Leetcode454.四数相加II
本题还是利用了map[n]++,然后后面再判断map[sum-n]有没有值,哈希类的题目套路都差不多。
注意
C++中map可以不用初始化,索引时没有对应key的话自动插入。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
int result=0;
unordered_map<int,int> map12;
for(int i=0;i<nums1.size();i++){
for(int j=0;j<nums2.size();j++){
map12[nums1[i]+nums2[j]]++;
}
}
for(int i=0;i<nums3.size();i++){
for(int j=0;j<nums4.size();j++){
if(map12[-nums3[i]-nums4[j]]) result += map12[-nums3[i]-nums4[j]];
}
}
return result;
}
};
Leetcode383. 赎金信
数组这个也是,count[n]++,然后判断count[m]有没有值。
太过简单不多说了
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int count[26]={0};
for(int i=0;i<magazine.size();i++){
count[magazine[i]-'a']++;
}
for(int j=0;j<ransomNote.size();j++){
if(count[ransomNote[j]-'a']){
count[ransomNote[j]-'a']--;
}
else return false;
}
return true;
}
};
Leetcode15. 三数之和
这难度一下就上来了
本题最难的在于对重复性的判断,要实现既能在子数组中重复,又不能有重复的子数组。
没做出来,看答案了,这道题高效的方案是双指针法,如下:
本质上是先排序,然后遍历,大循环是i,然后判断对于nums[i]而言,left和right所指的值是否满足条件。
最精髓的地方就是先sort了一下,有序之后如果和大了就right–,如果和小了就left++
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0) return result;
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
if (nums[i] + nums[left] + nums[right] > 0) right--;
else if (nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back(vector<int>{nums[i], nums[left], nums[right]});
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
return result;
}
};
精髓
- 开头进行的排序,为双指针的运行提供了基础的有序环境
sort(nums.begin(),nums.end());
- 指针判重条件,应该是先用一次,第二次遇到就跳过
if (i > 0 && nums[i] == nums[i - 1]) { continue; }
Leetcode 18. 四数之和
和三数之和一样,剪枝操作不太一样,要注意一下。
自己写的如下:
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
vector<vector<int>> result;
if(nums.size()<4) return result;
for(int i=0;i<nums.size();i++){
if(i>0 && nums[i]==nums[i-1]) continue;
for(int j=i+1;j<nums.size()-2;j++){
if(j>i+1 && nums[j]==nums[j-1]) continue;
int left=j+1;
int right=nums.size()-1;
while(left<right){
if((long)nums[i]+nums[j]+nums[left]+nums[right]>target) right--;
else if((long)nums[i]+nums[j]+nums[left]+nums[right]<target) left++;
else{
result.push_back(vector<int>{nums[i],nums[j],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;
}
};
和答案相比缺少剪枝操作因为没想出来怎么跟target比,可以加上if (nums[k] > target && nums[k] >= 0) break;
和if (nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) break;