以下是今日份的总结
454.四数相加II
383. 赎金信
15. 三数之和
18. 四数之和
454 重点在于对a+b = -(c+d) 的判断上;
383 对map中参数对应key的value判断;
15 双指针相对于哈希表方法更便捷;
18 类似于三数之和的双指针解法。
今天的题目有的用哈希表做起来顺畅,有的用双指针法做起来顺畅,需要多多回看才行^ _ ^
四数相加II
思路:
四个整数数组,等长,长度为n,要求返回(i,j,k,l)的组合数量,
使用map记录key a+b的值 value a+b出现的次数
值得注意的是
用unordered_map中的find()函数查找-(c+d)的映射
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
int n = nums1.size();
unordered_map<int,int> m1 ;
for(int a :nums1){
for(int b:nums2){
++m1[a+b];
}
}
int count = 0;
for(int c :nums3){
for(int d:nums4){
if(m1.find(0-(c+d))!=m1.end()){
count +=m1[0-(c+d)];
}
}
}
return count;
}
赎金信
思路:
将string放入map中,匹配ransomNote和magazine的key对应的value值,当ransomNote中字符出现次数大于 magazine中字符出现次数时,判断为否,循环结束没有返回否即为真。
值得注意的是
magazine 中的每个字符只能在 ransomNote 中使用一次
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char, int> m1;
unordered_map<char, int> m2;
for (char a : ransomNote) {
++m1[a];
}
for (char b : magazine) {
++m2[b];
}
for (auto& [k, v] : m1) {
if (v > m2[k])
return false;
}
return true;
}
三数之和
思路:
nums[i] = a ; nums[j] = b; nums[k] = -(a+b)
值得注意的是
答案中不可以包含重复的三元组
满足 i != j、i != k 且 j != k
nums[i] + nums[j] + nums[k] == 0
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> res;
for (int i = 0; i < n; i++) {
if (nums[i] > 0) {
return res;
}
// 三元组去重
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int k = n - 1;
int target = -nums[i];
for (int j = i + 1; j < n; j++) {
// 三元组去重
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
//确保j在k的左边
while (j < k && nums[j] + nums[k] > target) {
k--;
}
if (j == k)
break;
if (nums[j] + nums[k] == target) {
res.push_back({nums[i], nums[j], nums[k]});
}
}
}
return res;
}
四数之和
思路:
先排序,在递增顺序下的判断会好做很多
值得注意的是
不重复的四元组 [nums[a], nums[b], nums[c], nums[d]]
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
int n = nums.size();
if (n < 4)
return res; // nums长度小于4,直接返回空值
sort(nums.begin(), nums.end()); // 先排序
for (int i = 0; i < n - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1])
continue; // 去重
if ((long)nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] >target)
break; // 当连续四个值的和超过target是,直接返回
if ((long)nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] <target)
continue; // 当前值和最大的三个值小于target,说明当前值太小,遍历至下一循环
for (int j = i + 1; j < n - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if ((long)nums[i] + nums[j] + nums[j + 1] + nums[j + 2] >target) {
break;
}
if ((long)nums[i] + nums[j] + nums[n - 2] + nums[n - 1] <target) {
continue;
}
int left = j + 1,
right = n - 1; // 左指针指向j的下一位,有指针指向数组末尾
while (left < right) {
long sum =
(long)nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
res.push_back(
{nums[i], nums[j], nums[left], nums[right]});
// left 去重
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
// right 去重
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return res;
}
写在最后
----OK,今日份的博客就写到这里,昨天的题没想明白,今天花了点时间弄懂了,明天继续加油!!!
—几数之和。。。看来还是双指针好用;
–追上时间进度了吗?如追,还需加油!!(笑
-可以讨厌老师,但是不要讨厌知识。