454、四数相加Ⅱ、383、赎金信
、15、三数之和四数之和
四数相加
对于四数相加,我们可以定义一个map用来记录nums1与nums2的和对应次数,再遍历nums3与nums4,如果存在c与d使得a、b、c、d之和为零,我们就记录下这个次数,最后使这个次数相加即可。
代码如下:
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map <int,int> map1;
for(auto a:nums1)
for(auto b:nums2)
{
map1[a+b]++;
}
int count = 0;
for(auto c:nums3)
for(auto d:nums4)
if(map1.find(-c-d)!=map1.end())
count+=map1[-c-d];
return count;
}
383、赎金信
首先,我们可以定义一个map,用于记录magzine中的元素次数,遍历一次magzine,让map中对应的次数+1;然后遍历一次ransomNote,让map中对应的次数-1,如果这个次数在访问完某个元素后小于零了,我们就返回false;如果顺利遍历完ransomNote数组,那我们就返回true;
代码
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<int,int> map1;
for(auto mag:magazine)
map1[mag-'a']++;
for(auto ran:ransomNote)
{
map1[ran-'a']--;
if(map1[ran-'a']<0)
return false;
}
return true;
}
};
15、三数之和
对于三数之和,由于题干没有要求是否有序,也没有要求要返回下标,因此我们可以先给他们进行排序。
我们可以定义三个指针,包括遍历指针,左指针和右指针,其中,遍历指针用来遍历该数组,左指针指的是遍历指针右侧的左端指针,右指针指的是遍历指针右侧的右端指针。如图
因为我们已经对数组进行了排序,因此 数组是从小到大的顺序。
对于每一个遍历的ii,如果满足
nums[ii]>0 说明右侧的元素都大于零,因此无需再遍历
如果满足
num[ii]+num[left]+num[righgt]==0 我们就将这三个数保存起来
那么我们将这三个元素保存起来,如果
num[ii]+num[left]+num[righgt]<0 说明三个数太小了,我们让left右移,使三个数大一点
如果
num[ii]+num[left]+num[righgt]>0 说明三个数太大了,我们让right左移,使三个数小一点
然而如果仅仅这样做,一定会有重复的元素,那么该如何去重呢?
当我们移动指针时,我们可以判断移动指针前后,指针是否重复,如果重复,让它们再移动一位。
对于ii而言
为了避免指针越界,我们可以让ii>0时进行判断,如果nums[ii]==nums[ii-1]时,让ii右移,即ii已经判别过了,无需判别相同的元素
对于left与right,处理方法相同,当我们访问到满足条件的left与right时,我们判断left与left+1所指是否相同,如果相同让left指向下一个指针,right同理,这样之后,让left与right分别向内移动即可。
代码
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>>answer;
for(int ii =0;ii<nums.size();ii++)
{
if(nums[ii]>0)
return answer;
if(ii>0&&nums[ii]==nums[ii-1])
continue;
int left = ii+1;
int right = nums.size()-1;
while(left<right)
{
if(nums[ii]+nums[left]+nums[right]==0)
{
answer.push_back(vector<int>{nums[ii],nums[left],nums[right]});
while(left<right&&nums[left]==nums[left+1])
++left;
while(left<right&&nums[right]==nums[right-1])
--right;
++left;
--right;
}
else if(nums[ii]+nums[left]+nums[right]<0)
++left;
else
--right;
}
}
return answer;
}
};
四数之和
与上面三数之和的题目类似,只不过需要双重for循环遍历该数组,并且不能设置ii>target的情况,最坑的是,这道题判定案例有一个是溢出了,因此我们对四个数进行相加时要进行转换为long类型。
代码
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> answer;
sort(nums.begin(),nums.end());
for(int ii = 0;ii<nums.size();ii++)
{
while(ii>0&&ii<nums.size()&&nums[ii]==nums[ii-1]) ++ii;
for(int jj = ii+1;jj<nums.size();jj++)
{ while(jj>(ii+1)&&jj<nums.size()&&nums[jj]==nums[jj-1]) ++jj;
int left = jj+1;
int right = nums.size()-1;
while(left<right)
{
if((long)nums[ii]+nums[jj]+nums[left]+nums[right]>target) --right;
else if((long)nums[ii]+nums[jj]+nums[left]+nums[right]<target) ++left;
else
{
answer.push_back(vector<int>{nums[ii],nums[jj],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 answer;
}
};