454.四数相加,利用哈希表查询简单的优点,化简时间复杂度,可以两组凑一对将其和存在哈希表中,在利用补数进行查询即可,此时时间复杂度为O(n^2),空间复杂度为O(1)。代码如下:
#include <iostream>
#include <vector>
#include <unordered_map>
int fourSumCount(std::vector<int> &A, std::vector<int> &B, std::vector<int> &C, std::vector<int> &D)
{
std::unordered_map<int, int> sumAB; // 存储A和B所有可能和的次数
int count = 0;
// 计算A和B所有可能的和,并记录每个和出现的次数
for (int a : A)
{
for (int b : B)
{
sumAB[a + b]++;
}
}
// 计算C和D所有可能的和,并查找是否有相反数存在
for (int c : C)
{
for (int d : D)
{
int sumCD = c + d;
// 如果sumAB中存在与C和D的和相反的数,则存在符合条件的四元组
if (sumAB.count(-sumCD))
{
count += sumAB[-sumCD];
}
}
}
return count;
}
int main()
{
std::vector<int> A = {1, 2};
std::vector<int> B = {-2, -1};
std::vector<int> C = {-1, 2};
std::vector<int> D = {0, 2};
std::cout << "Total tuples: " << fourSumCount(A, B, C, D) << std::endl;
return 0;
}
383. 赎金信,和242.有效的字母异位词 (opens new window)很像,但是不能重复,可以用哈希表简单实现,代码如下:
#include <iostream>
#include <unordered_map>
#include <string>
bool canConstruct (const std::string& string1,const std::string& string2){
std::unordered_map<char,int> charcount;
for(char s:string1){
charcount[s]++;
}
for(char t:string2){
if(charcount[t] == 0){
return false;
}else{
charcount[t]--;
}
}
return true;
}
int main(){
std::string ransomNote = "aa";
std::string magazine = "aab";
if (canConstruct(magazine,ransomNote)) {
std::cout << "true" << std::endl;
} else {
std::cout << "false" << std::endl;
}
return 0;
}
15. 三数之和,与上述题型中只需返回组合个数的题型不同,此题需要返回所有组合并去重,因此简单使用哈希表并不能简单求解该问题,需要利用双指针来求解题目,并设计合理的去重检测,代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<std::vector<int>> threeSum(std::vector<int> &nums)
{
std::sort(nums.begin(), nums.end());
std::vector<std::vector<int>> res;
for (int i = 0; i < nums.size(); ++i)
{
if (i > 0 && nums[i] == nums[i - 1]) // 每回合都把一个数确定的可能性包括了,所以有一样的直接pass
{
continue;
}
int left = i + 1, right = nums.size() - 1;
while (left < right)
{
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0)
{
res.push_back({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--;
}
else if (sum < 0)
{
left++;
}
else
{
right--;
}
}
}
return res;
}
int main()
{
std::vector<int> nums = {-1, 0, 1, 2, -1, -4};
std::vector<std::vector<int>> result = threeSum(nums);
for (const auto &triplet : result)
{
std::cout << "[" << triplet[0] << ", " << triplet[1] << ", " << triplet[2] << "]\n";
}
return 0;
}
18. 四数之和,和上一道题目原理相同,只不过多加了一层for循环来实现,代码如下:
#include <iostream>
#include <vector>
#include <algorithm>
std::vector<std::vector<int>> fourSum(std::vector<int> &nums, int target)
{
std::vector<std::vector<int>> res;
if (nums.size() < 4)
return res;
std::sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size() - 3; ++i)
{
if (i > 0 && nums[i] == nums[i - 1])
continue; // 跳过重复的数
for (int j = i + 1; j < nums.size() - 2; ++j)
{
if (j > i + 1 && nums[j] == nums[j - 1])
continue; // 跳过重复的数
int left = j + 1, right = nums.size() - 1;
while (left < right)
{
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target)
{
res.push_back({nums[i], nums[j], 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 (sum < target)
{
left++;
}
else
{
right--;
}
}
}
}
return res;
}
int main()
{
std::vector<int> nums = {1, 0, -1, 0, -2, 2};
int target = 0;
std::vector<std::vector<int>> result = fourSum(nums, target);
for (const auto &quad : result)
{
std::cout << "[" << quad[0] << ", " << quad[1] << ", " << quad[2] << ", " << quad[3] << "]\n";
}
return 0;
}