454.四数相加II
题目链接:454.四数相加II
寻找两个数组之和,是否与另外两个数组之和有特定的关系。
因为数值可能跨度太大,选择使用下标表示为对应的数值大小,会很浪费内存空间。
target
减去后两个数组之和的结果,是否存在与前两个数组之和组成的集合中。又要返回满足题意的次数,因此决定使用map
而不是set
。
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> map;
for (auto num1 : nums1) {
for (auto num2 : nums2) {
map[num1 + num2]++;//nums1 nums2之和存入map
}
}
int res = 0;
for (auto num3 : nums3) {
for (auto num4 : nums4) {
auto target = 0 - (num3 + num4);//查找target是否存在与map中
if (map.find(target) != map.end()) {
res += map[target];//target对应存在多少个,都加入
}
}
}
return res;
}
};
383. 赎金信
题目链接:383. 赎金信
判断ransomNote
中的字符是否出现在magazine
中。
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
if (ransomNote.size() > magazine.size()) {
return false;
}
int record['z' - 'A' + 1] = {};//个数别查错了。+1
for (auto& i : magazine) {
record[i - 'A']++;
}
for (auto& i : ransomNote) {
record[i - 'A']--;
//出现就直接返回,不用在该循环之后再遍历record
if (record[i - 'A'] < 0) return false;
}
return true;
}
};
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char, int> map;
for (auto letter : magazine) {
map[letter]++;
}
for (auto letter : ransomNote) {
if (map.find(letter) != map.end() && map[letter]) {
map[letter]--;
} else {
return false;
}
}
return true;
}
};
15. 三数之和
题目链接:15. 三数之和
两个数之和,第三个数与目标值运算之后,是否出现在两个数之和中。
但是,时间复杂度为
O
(
n
2
)
O(n^2)
O(n2),且要去重操作。
选择使用双指针,注意去重操作。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int> > ret;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
if (nums[i] > 0) break;//剪枝。没有不影响结果
//i指针的去重,因为i-1已经计算过了,因此需要跳过i
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1, 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 {
ret.push_back({nums[i], nums[left], nums[right]});
//left和right指针的去重。移动时,注意满足边界条件
while (left < right && nums[left] == nums[left + 1])
left++;
while (left < right && nums[right] == nums[right - 1])
right--;
left++;
right--;
}
}
}
return ret;
}
};
其中
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
前两行和后两行顺序不能调换。
18. 四数之和
题目链接: 18. 四数之和
三数之和再多套一个遍历。不用哈希理由三数之和。
注意剪枝条件不同于三数之和,因为三数的target
是0
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(), nums.end());
for (int idx = 0; idx < nums.size(); ++idx) {
if (nums[idx] >= 0 && nums[idx] > target) break;//剪枝,由于target可能小于零,所以要两个条件
if (idx > 0 && nums[idx] == nums[idx - 1]) continue;//去重
for (int idx2 = idx + 1; idx2 < nums.size(); ++idx2){
if (nums[idx] + nums[idx2] >= 0 && nums[idx] + nums[idx2] > target) break;//剪枝
if (idx2 > idx + 1 && nums[idx2] == nums[idx2 - 1]) continue;//去重
int left = idx2 + 1, right = nums.size() - 1;
while (left < right) {
if (static_cast<long>(nums[idx]) + nums[idx2] + nums[left] + nums[right] < target) {
++left;
} else if (static_cast<long>(nums[idx]) + nums[idx2] + nums[left] + nums[right] > target) {
--right;
} else {
res.push_back({nums[idx], nums[idx2], 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 res;
}
};
if (static_cast<long>(nums[idx]) + nums[idx2] + nums[left] + nums[right] < target)
long
是因为nums数组中的元素相加之后溢出int
范围,只要将其中一个改为long
都可以