一、四数相加
这题又是一道用map来解决的问题,本题的核心思路在于,把nums1,nums2两个数组看成一个整体,依次对他们进行遍历,并且把不同求和结果放到map里。其中,map的key值是两数之和,value是两数之和出现的次数。
随后,再把nums3,nums4看成一个整体,这样把4个数组变成两个数组,转换成昨天做的两数之和的问题了。
今天运用的map操作和昨天相比,今天采用了umap[a+b]++直接对相同key值进行value自增,相当于一个计数器,而昨天是用map来作为一个存储工具,用的是.insert({})添加键值对的方法。
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;
}
};
二、赎金信
简单的数组哈希表,我的实现思路是,把magezine这个字符串先存起来,表示可用的字母数量,然后遍历ranstomNote数组,对哈希表内的次数进行递减,最后检查哈希数组,如果出现负数,就代表着有不够用的字母,返回false,否则就返回true
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int hash[1000]={0};
for(int j=0;j<magazine.size();j++){
hash[magazine[j]-'a']++;
}
for(int i=0;i<ransomNote.size();i++){
hash[ransomNote[i]-'a']--;
}
for(int k=0;k<1000;k++){
if(hash[k]<0)return false;
}
return true;
}
};
三、三数之和
这道题没有参考用哈希表的方法,用的是双指针。
这题有一个知识点是,如果返回值需要返回下标,那么就不能进行排序操作,不需要返回下标值的话就可以排序后再做。
本题涉及到了去重的操作,去重也分两种,一种是不与前面重复,一种是不与后面重复。在遍历下表i经过的元素时,采用的是不与前面重复,而后面在移动left和right指针去重的时候left是不与后面重复(left与left+1比较)right与right-1比较。
本题的整体思路是:
1.首先先将原数组排序,然后确定下标对应的元素值,再运用双指针看看能否找出来另外两个满足条件的数。
2.在遍历数组元素的时候,如果首元素就大于0,那么后面的求和也一定大于0,直接跳出整个循环(break或return)。如果能够正常遍历,i>0的时候,再判断新遍历的元素和之前遍历过的元素是否重复,如果有重复跳出本次循环(continue)。
3.在确定下标元素以后,双指针查值的时候,也要考虑去重的操作。这个去重操作要保证,left以后与left对应值相同的所有元素都要被覆盖过去,right之前所有的被覆盖。在写这一步while条件的时候,要先让left<right,再写其他条件,否则容易出现溢出的报错
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
int left,right;
vector<vector<int>>result;
for(int i=0;i<nums.size();i++){
left=i+1;
right=nums.size()-1;
if(nums[i]>0)break;
if(i>0&&nums[i]==nums[i-1]){
continue;
}
while(left<right){
if(nums[left]+nums[right]+nums[i]>0){
right--;
}
else if(nums[left]+nums[right]+nums[i]<0){
left++;
}
else{
result.push_back(vector<int>{nums[i],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;
}
};
四、四数之和
相较于三数之和,本题多加了一层循环遍历,同时意味着多一次去重剪枝的操作。
第一次剪枝:让首元素保证不大于目标值,并且不能为负值,因为负数越加越小
第一次去重:下标大于0,不与前重复
第二次剪枝:让首元素(已经变成了两个元素相加)保证不大于目标值,并且不为负
第二次去重:让j在i后一位,也就是让原来的i在0以后
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
vector<vector<int>>result;
for(int i=0;i<nums.size();i++){
if(nums[i]>target&&target>0&&nums[i]>=0){
break;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
for(int j=i+1;j<nums.size();j++){
int left=j+1;
int right=nums.size()-1;
if(nums[j]+nums[i]>target&&target>0)break;
if(j>i+1&&nums[j]==nums[j-1])continue;
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{
while(left<right&&nums[left]==nums[left+1])left++;
while(left<right&&nums[right]==nums[right-1])right--;
result.push_back(vector<int>{nums[i],nums[j],nums[left],nums[right]});
left++;
right--;
}
}
}
}
return result;
}
};
在其中测试的一组数据中,提示数据溢出,说明int类型不够存放,这里就涉及到了一个新的知识点,在前面加(long)进行转换