454.四数相加 II
这道题的思路可以参照二数之和的思路,不过这道题需要先把两个数组的加和作为一组,另外两个数组的加和作为一组,再参照两数之和的思路。
用map存放数组加和以及次数;
遍历nums12,将它们每两个数的加和存放到hash12里,另外两个数组同理;再遍历map,找合适的目标值x。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
map<int,int> hash12,hash34;
int sum12,sum34,ans=0;
for(int i=0;i<nums1.size();i++){
for(int j=0;j<nums2.size();j++){
sum12=nums1[i]+nums2[j];
hash12[sum12]++;
}
}
for(int i=0;i<nums3.size();i++){
for(int j=0;j<nums4.size();j++){
sum34=nums3[i]+nums4[j];
hash34[sum34]++;
}
}
for(auto m:hash34){
int x=0-m.first;
if(hash12.find(x)!=hash12.end()) ans+=hash12[x]*m.second;
}
return ans;
}
};
383.赎金信
这道题的难度并不大,题意是说能不能使用杂志里面的字符来组成赎金信,其实就是想知道A字符串的字符是否都在B字符串中都出现过。
可以使用map解决这个题。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
map<char,int> mgz;
int flag=0;
for(int i=0;i<magazine.length();i++) mgz[magazine[i]]++;//使用map统计杂志字符以及出现次数
for(int i=0;i<ransomNote.length();i++){
flag=0;//初始化,假定赎金信每个字符一开始都是在杂志里面找不到的
if(mgz.find(ransomNote[i])!=mgz.end()&&mgz[ransomNote[i]]!=0){
//字符在杂志出现过且出现次数不为0
mgz[ransomNote[i]]--;
flag=1;
}
if(flag==0) break;
}
if(flag) return true;
else return false;
}
};
读完题很自然会想到map,但是题目说“ransomNote
和 magazine
由小写英文字母组成”,那么为了进一步优化空间,可以采用数组来解决。(因为使用map的空间消耗要比数组大一些)
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int mgz[26];
int flag=0;
for(int i=0;i<magazine.length();i++) mgz[magazine[i]-'a']++;
for(int i=0;i<ransomNote.length();i++){
flag=0;
if(mgz[ransomNote[i]-'a']){
mgz[ransomNote[i]-'a']--;
flag=1;
}
if(flag==0) break;
}
if(flag) return true;
else return false;
}
};
15.三数之和
这个题属实是被难住了,三元组去重真的是一个难点了。看了题解之后才弄懂了思路。
首先对数组进行排序(为了更好的去重)
进行数组遍历,i从下标0的地方开始,同时下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。
如果nums[i] + nums[left] + nums[right] > 0
就说明 此时三数之和大了,因为数组已经排过序,所以right–,使得三数之和变小。
同理, 如果nums[i] + nums[left] + nums[right] < 0
就说明 此时三数之和小了,所以left++,使得三数之和变大。
left和right是在往中间靠拢的,而且题目要求是三元组,所以循坏的判断条件应该是left<right
(不取等于是因为如果left=right时就变成两个数而不是三个数了)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size();i++){
int l=i+1,r=nums.size()-1;//l与r的赋值放在循环内部,确保在每次迭代时都会对 l 和 r 进行重新赋值
if(nums[i]>0) break;
if(i>0&&nums[i]==nums[i-1]) continue;//第一个数的去重:说明在前面已经处理过,判断条件要注意加上i>0
while(l<r){
if(nums[i]+nums[l]+nums[r]>0) r--;
else if(nums[i]+nums[l]+nums[r]<0) l++;
else{
//三数之和为0
res.push_back(vector<int>{nums[i],nums[l],nums[r]});
//两个边界去重判断
while(l<r&&nums[r]==nums[r-1]) r--;
while(l<r&&nums[l]==nums[l+1]) l++;
l++;
r--;
}
}
}
return res;
}
};