四数相加
这道题可以直接使用4个for循环去求解,但是这样时间复杂度会高很多,我们可以将四个数组两两拆分,使用unordered_map容器去求解问题,首先我们遍历nums1和nums2两个数组,将其中的元素之和设置成key,将元素之和出现的次数设置成value。对于这个数组来说
nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
map容器中就有key=-1,value =1;key=0,value=2;key=1,value=1;接下来,遍历nums3和nums4中的数,这时候我们需要判断的是-(c+d)是否在map中出现过,要是出现过,那么计数器就可以直接加上已经出现过的次数。要是还是另外出现过,就继续加。代码如下:
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;
}
};
赎金信
这道题还是很简单的,可以直接使用两个for循环暴力求解。直接给出代码:
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;
}
};
这道题可以换一种思路,题目要求是判断ransomNote中字符能不能被magazine中的字符构成。我们可以将magazine中字符放入一个数组中,然后我们判断ransomNote中字符在这个数组中有没有出现,这样就转换成了一个哈希表的问题。
这道题和前面的异位词相同,都是使用数组作为哈希表来解题。
这里record[magazine[i]-'a']++来举个例子,magazine数组为aab的话,那么在数组中0号位置记录2,1号位置记录1,其余位置记录0。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26] = {0};
if(ransomNote.length() > magazine.length()){
return false;
}
for(int i = 0;i < magazine.length();i++)//将magazine中的元素放入到数组中
{
record[magazine[i] - 'a']++;
}
for(int i = 0;i < ransomNote.length();i++)
{
record[ransomNote[i] - 'a']--;
if(record[ransomNote[i]- 'a'] < 0)
{
return false;
}
}
return true;
}
};
三数之和![](https://i-blog.csdnimg.cn/blog_migrate/0d0b1e3dbc233fdb9de6aacfa873919f.png)
这道题和前面的四数相加是有区别的,前面的四数相加不需要去重的操作,所有用哈希表的做法来做的很简单,考虑到这题也可以用哈希表的思想,但是后序需要进行去重的操作,因此不适合用哈希表。
首先,我们先对数组进行排序,我们从前往后遍历整个数组,第一个数为i、第二个数为left、第三个数为right。我们需要得到的结果是nums[i]+nums[left]+nums[right]=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;//如果第一个数就大于0,后面所有的数都大于0
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(right > left &&nums[left] == nums[left+1]) left++;//对第二个数进行去重
while(right > left && nums[right] == nums[right-1]) right--;//对第三个数进行去重
right--;
left++;
}
}
}
return result;
}
};
四数之和
这道题的思想和三数之和一样,使用双指针法,只不过是在i的前面加了一个k,然后使用两个for循环遍历,重点在于,需要对k和i进行剪枝操作,去重操作相类似。
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
sort(nums.begin(),nums.end());
for(int k = 0;k < nums.size();k++)
{
//对k进行减枝操作
if(nums[k] > target && nums[k] >= 0) break;
//对k进行去重
if(k > 0 && nums[k] == nums[k-1]) continue;
for(int i = k+1;i < nums.size();i++)
{
//对i进行剪枝
if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) break;
//对i进行去重
if(i > k+1 && nums[i] == nums[i-1]) continue;
int left = i + 1;
int right = nums.size() - 1;
while(right > left)
{
if((long)nums[k]+nums[i]+nums[left]+nums[right] > target) right--;
else if((long)nums[k]+nums[i]+nums[left]+nums[right] < target) left++;
else{
result.push_back(vector<int>{nums[k],nums[i],nums[left],nums[right]});
while(right > left && nums[left] == nums[left+1]) left++;//对left去重
while(right > left && nums[right] == nums[right-1]) right--;//去right去重
right--;
left++;
}
}
}
}
return result;
}
};