454.四数相加
这道题要求找的是从四个数组中各挑一个元素找加起来等于0的组合的个数,按照常规的暴力解,肯定就是四个for循环遍历,找到了,count++;但是这样子的时间复杂度太高了,所以需要想一下降低时间复杂度的方法,因此有了两两组合的方法,也就是先遍历第一个和第二个的数组,把他们的和以及出现的次数记录在map里面,然后遍历第三个和第四个数组,看看0-(c+d)是否存在map里面,存在的话,count+=记录在map里面的值,两两组合的话时间复杂度就是O的平方,因为是两个for循环。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2,
vector<int>& nums3, vector<int>& nums4)
{
unordered_map<int,int>umap;
for(int a:nums1)
{
for(int b:nums2)
{
umap[a+b]++;
}
}
int count=0;
for(int c:nums3)
{
for(int d:nums4)
{
if(umap.find(0-(c+d))!=umap.end())
{
count+=umap[0-(c+d)];
}
}
}
return count;
}
};
383.赎金信
1.暴力解法
因为要查找magazine的字符串的字母能否拼成ransomNote,(注意,magazine的字母只能用一次),所以我们可以遍历magazine的字母,然后遍历ransomNote,即双层遍历,这样的话,一旦在magazine的字母有在ransomNote,那么所对应ransomNote的字母就移除。最后看ransomNote的字符串长度是否为0,如果为0的话说明magazine的字符串的字母可以拼成ransomNote。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2,
vector<int>& nums3, vector<int>& nums4)
{
unordered_map<int,int>umap;
for(int a:nums1)
{
for(int b:nums2)
{
umap[a+b]++;
}
}
int count=0;
for(int c:nums3)
{
for(int d:nums4)
{
if(umap.find(0-(c+d))!=umap.end())
{
count+=umap[0-(c+d)];
}
}
}
return count;
}
};
2.哈希法
哈希法的解法跟242判断有效的字母异位词相似,先用数组存储ransomNote每一个字母的出现次数,用asciii码-‘a’作为数组的下标,然后再遍历magazine,magazine的字母-'a'所对应的数组元素--,如果record[i]>0,说明ransomNote里面有的字母在magazine是没有的或者是个数不够凑成ransomNote,因为如果个数刚好可以凑或者有多余的字母,对应的数组的值是会<=0的。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
// for(int i=0;i<magazine.length();i++)
// {
// for(int j=0;j<ransomNote.length();j++)
// {
// if(magazine[i]==ransomNote[j])
// ransomNote.erase(ransomNote.begin()+j);
// break;
// }
// }
// if(ransomNote.length()==0)
// return true;
// return false;
int record[26]={0};
for(int i=0;i<ransomNote.length();i++)
{
record[ransomNote[i]-'a']++;
}
for(int i=0;i<magazine.length();i++)
{
record[magazine[i]-'a']--;
}
for(int i=0;i<26;i++)
{
if(record[i]>0)
return false;
}
return true;
}
};
15.三数之和
这是一道坑点贼多的题,第一步要先将数组排序!!!!!最主要的就是要去重,第一层去重,是在找与nums[i]匹配的集合,去重的点在于while(nums[left]==nums[left+1]&&left<right) left++; while(nums[right]==nums[right-1]&&left<right) right--;这一步是为了确保在搜集的过程中不会出现重复的情况,如果元素相同,那么指针都会往右或往左移,第二层去重,是去重和nums[i]==nums[i-1]相同的情况,因为如果nums[i]==nums[i-1],那说明nums[i]这个元素的集合已经在之前搜集nums[i-1]的时候找过了,所以这时候指向i的指针可以往后移动,注意在这里判断条件要是i>0&&nums[i]==nums[i-1],因为如果i=0的话,那访问是非法的,会报错。
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(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 (vector<int>{nums[i],nums[left],nums[right]});
while(nums[left]==nums[left+1]&&left<right)
left++;
while(nums[right]==nums[right-1]&&left<right)
right--;
left++;
right--;
}
}
}
return result;
}
};
18.四数之和
四数之和简直就是三数之和的超强plus版,与三数之和不同的是在移动left+right指针前要进行两次循环,其中每一次循环都有去重和剪枝的操作,
if(nums[i]>target&&nums[i]>=0)
break;
这里要加上nums[i]>0的原因是因为这个数组中可能有负数,target也可能是负数,假如target=-5,nums[0]=-4,nums[1]=-1,nums[2]=0,nums[3]=0,那么这时候是找得出加起来等于target的集合的,所以咱们得限制num[i]>0才可以剪枝,不然像这种情况是不可以剪枝的。
if(i>0&&nums[i]==nums[i-1])
continue;
这是去重的操作,因为如果nums[i]==nums[i-1]那么说明这个元素在查找num[i-1]的时候已经被用到了,所以咱们可以再继续往后移找没有用过的新元素。
这道题的其它代码和三数之和很像,基本就是 套娃再套娃。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>>result;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++)
{
if(nums[i]>target&&nums[i]>=0)
break;
if(i>0&&nums[i]==nums[i-1])
continue;
for(int j=i+1;j<nums.size();j++)
{
if(nums[i]+nums[j]>target&&nums[i]+nums[j]>=0)
break;
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(nums[right]==nums[right-1]&&left<right)
right--;
while(nums[left]==nums[left+1]&&left<right)
left++;
right--;
left++;
}
}
}
}
return result;
}
};