1、四数相加II
#include <iostream>
#include <unordered_map>
#include <vector>
using namespace std;
class Solution {
public:
int fourSumCount(vector<int> &A, vector<int> &B, vector<int> &C, vector<int> &D) {
unordered_map<int, int> umap; //key:a+b的数值,value:a+b数值出现的次数
// 遍历A和B数组,统计两个数组元素之和,和出现的次数,放到map中
for (int a: A) {
for (int b: B) {
umap[a + b]++; //如果键不存在,会创建一个新的键值对,且++后为1
}
}
int count = 0; // 计数器,统计 a+b+c+d=0 出现的次数
// 在遍历C和D数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
for (int c: C) {
for (int d: D) {
if (umap.find(-(c + d)) != umap.end()) {
count += umap[-(c + d)];
}
}
}
return count;
}
};
int main() {
vector<int> A{1, 2};
vector<int> B{-2, -1};
vector<int> C{-1, 2};
vector<int> D{0, 2};
Solution solution;
cout << solution.fourSumCount(A, B, C, D);
}
2、赎金信
先用两层for
循环暴力解法:
#include <iostream>
using namespace std;
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
if (ransomNote.size() > ransomNote.size())
return false;
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); // ransomNote删除这个字符
break;
}
}
}
return ransomNote.empty(); //如果为空,返回true
}
};
int main() {
string str1 = "aa";
string str2 = "aab";
Solution solution;
cout << solution.canConstruct(str1, str2);
}
利用哈希法:
#include <iostream>
using namespace std;
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26]{0}; //因为只有小写字母
if (ransomNote.size() > magazine.size())
return false;
for (int i = 0; i < magazine.length(); ++i)
record[magazine[i] - 'a']++;
for (int j = 0; j < ransomNote.length(); ++j) {
record[ransomNote[j] - 'a']--;
// 如果小于零说明ransomNote里出现的字符,magazine没有
if (record[ransomNote[j] - 'a'] < 0)
return false;
}
return true;
}
};
int main() {
string str1 = "aa";
string str2 = "aab";
Solution solution;
cout << solution.canConstruct(str1, str2);
}
3、三数之和
先用暴力解法,这种方法需要考虑复杂的边界情况,极为繁琐:
#include <iostream>
#include <unordered_set>
#include <vector>
using namespace std;
class Solution {
public:
vector<vector<int>> threeSum(vector<int> &nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// a = nums[i], b = nums[j], c = -(a + b)
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0) // 排序之后如果第一个元素已经大于零,那么不可能凑成三元组,这里始终保持nums[i]是最小值
break;
if (i > 0 && nums[i] == nums[i - 1]) //三元组元素a去重
continue; //pass
unordered_set<int> uset; //特点是无序,元素无重复
for (int j = i + 1; j < nums.size(); ++j) {
if (j > i + 2
&& nums[j] == nums[j - 1]
&& nums[j - 1] == nums[j - 2]) { // 三元组元素b去重
continue;
}
int c = 0 - (nums[i] + nums[j]);
if (uset.find(c) != uset.end()) {
result.push_back({nums[i], nums[j], c});
uset.erase(c);// 三元组元素c去重
} else {
uset.insert(nums[j]);
}
}
}
return result;
}
};
int main() {
vector<int> nums{-1, 0, 1, 2, -1, -4};
Solution solution;
for (const auto& row: solution.threeSum(nums)) {
for (auto ele: row) {
cout << ele << " ";
}
cout << endl;
}
}
使用双指针法:
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
// a = nums[i], b = nums[left], c = nums[right]
for (int i = 0; i < nums.size(); ++i) {
if (nums[i] > 0)
return result; //也可以写 break;
if (i > 0 && nums[i] == nums[i - 1])
continue;
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
// 去重复逻辑如果放在这里,[0,0,0]的情况,可能直接导致 right<=left 了,从而漏掉了[0,0,0]这种三元组
/*
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
*/
if (nums[i] + nums[left] + nums[right] > 0) right--;
else if (nums[i] + nums[left] + nums[right] < 0) left++;
else {
result.push_back({nums[i], nums[left], nums[right]});
// 去重逻辑应该放在找到一个三元组之后,对b 和 c去重
while (right > left && nums[right] == nums[right - 1]) right--; //考虑[-3,1,1,1,1,2,2,2,2]边界情况
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
return result;
}
};
int main() {
vector<int> nums{-1, 0, 1, 2, -1, -4};
Solution solution;
for (const auto& row: solution.threeSum(nums)) {
for (auto ele: row) {
cout << ele << " ";
}
cout << endl;
}
}
4、四数之和
#include <iostream>
#include <vector>
using namespace std;
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) {
// 剪枝处理
if (nums[k] > target && nums[k] >= 0)
break;
// 对nums[k]去重
if (k > 0 && nums[k] == nums[k - 1])
continue;
for (int i = k + 1; i < nums.size(); ++i) {
// 2级剪枝处理
if (nums[k] + nums[i] > target && nums[i] >= 0) //这里nums[k]+nums[i]是一个整体
break;
// 对nums[i]去重
if (i > k + 1 && nums[i] == nums[i - 1])
continue;
int left = i + 1;
int right = nums.size() - 1;
while (right > left) {
// nums[k] + nums[i] + nums[left] + nums[right] > target 会溢出
if ((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
right--;
// nums[k] + nums[i] + nums[left] + nums[right] < target 会溢出
} else if ((long) nums[k] + nums[i] + nums[left] + nums[right] < target) {
left++;
} else {
result.push_back({nums[k], nums[i], nums[left], nums[right]});
// 对nums[left]和nums[right]去重
while (right > left && nums[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
// 找到答案时,双指针同时收缩
right--;
left++;
}
}
}
}
return result;
}
};
int main() {
vector<int> nums{1, 0, -1, 0, -2, 2};
int target = 0;
Solution solution;
for (const auto& row: solution.fourSum(nums, target)) {
for (auto ele: row) {
cout << ele << " ";
}
cout << endl;
}
}