今日任务: 454.四数相加II ,383. 赎金信 ,15. 三数之和 , 18. 四数之和 + 总结
状态:1刷
题目: 给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。
思路: This is a C++ implementation for the problem where we need to count the number of i, j, k, l
such that A[i] + B[j] + C[k] + D[l]
equals to zero
. The solution uses the concept of Hashmap
and the meet in the middle algorithm
.
The solution has four steps:
counter
代码:
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> umap;// key:a+b的数值,value:a+b数值出现的次数
// 遍历前两个数组,将两数之和以及出现次数存到 umap
// Traverse arrays A and B, calculate the sum, and store the frequency in the hashmap
for (int a : nums1){
for (int b : nums2 ){
umap[a + b]++;
}
}
int count = 0;
// 遍历后两个数组,若找到两数之和为 -(a+b),返回 value
// Travese arrays C and D, check if the negative sum exists in the hashmap, and update the counter
for (int c : nums3){
for (int d : nums4){
// 在 umap 中找到了 -(c+d) 后,存储 value
if (umap.find(0 - (c + d)) != umap.end()){
count += umap[0 - (c + d)];
}
}
}
return count;
}
};
时间复杂度: O(n^2)
空间复杂度: O(n^2)
The time complexity of this solution in O(n^2) because we loop through the arrays twice.
The space complexity is also O(n^2) because A and B could be different.
题目: Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.
Each letter in magazine can only be used once in ransomNote.
思路: 数组在哈希法中的应用: 用一个长度为26的数组还记录magazine里字母出现的次数。然后再用ransomNote去验证这个数组是否包含了ransomNote所需要的所有字母。
The solution uses an integer array record
of size 26(represent 26 alphabets) as a hashtable that stores the frequency of each character present in the magazine.
Here is how the solution works:
ransomNote
is greater than the size of the magazine
. if it is, then it immediately returns false because it would be impossible to construct the ransomNote
from the magazine
.magazine
string and for each chartcter, it increments the corresponding index value
in the record
array. The index is calculated by subtracting ‘a’ from the character(to get values from 0 - 25).(key
)ransomNote
string and for each character, it decrements the value in the record
array. If it encounter a character that makes the count in the record
array less than zero, it means this character appears more times in the ransomNote
than it does in the magazine
, it returns false.ransomNote
without finding any character that appears more times in the ransomNote
than in the magazine
, it returns true.The time complexity of this solution is O(n)
The space complexity is O(1).
Code:
// 数组在哈希法中的应用
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.size(); i++){
record[magazine[i] - 'a']++;
}
for (int j = 0; j < ransomNote.size(); j++){
record[ransomNote[j]- 'a']--;
if (record[ransomNote[j]- 'a'] < 0){
return false;
}
}
return true;
}
};
题目:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
思路:
因为三元组不能重复,所以 use sorting and 双指针方法 two-pointer technique to find unique triplets in the array that sum to zero.
sort(nums.begin(), nums.end())
, which is a important preprocessing step.Time and Space Complexity Analysis
The time complexity of this solution is O(n^2)
The space complexity is O(1)
代码:
// 双指针法
// 注意:不能重复,需要去重
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;// 2维数组
// a = nums[i], b = nums[left], c = nums[right]
// sort
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++){
if (nums[i] > 0){
return result;
}
// 对i去重 使用 nums[i] == nums[i - 1]
if (i > 0 && nums[i] == nums[i - 1]){
continue;
}
int left = i + 1;
int right = nums.size() - 1;
while (right > left){
// 指针收缩
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[right] == nums[right - 1]) right--;
while (right > left && nums[left] == nums[left + 1]) left++;
//
right--;
left++;
}
}
}
return result;
}
};
题目: 给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
思路:
在上一题的基础上加一个 loop . 剪枝与去重是细节需要注意
1.排序数组: 第一步是对数组进行排序。这使得可以应用双指针技巧。此外,它让我们能够以一种简单且有效的方式跳过重复的四元组。
2.遍历数组: 解决方案然后包含两个嵌套循环遍历数组。外循环变量k和内循环变量i分别是四元组的第一和第二个元素。
3.剪枝: 如果当前对的和nums[k] + nums[i]大于目标值,并且两个数都是非负数,我们就跳出内循环。这是因为,在一个已排序的数组中,如果在这一点上总和已经超过目标值,那么每一对后续的数也将超过目标值。
4.跳过重复项: 如果当前元素与前一个元素相同,我们将跳过此次循环迭代。这样做是为了避免在结果中多次包含相同的四元组。
5.应用双指针技巧: 对于四元组的第三和第四个元素,我们使用两个指针,left和right,它们开始时分别位于元素i的旁边和数组的末尾。然后这两个指针向着彼此的方向移动,直到它们相遇。在每一步,我们检查四个元素的和。如果和大于目标值,我们将right指针向左移动。如果和小于目标值,我们将left指针向右移动。如果和等于目标值,我们将四元组添加到结果中。
6.避免溢出: 在检查总和时,代码将总和转换为long,以避免整数溢出。
7.再次跳过重复项: 在我们找到一个四元组,其总和等于目标值后,我们将left和right指针向内移动,跳过任何重复的元素。这样做是为了避免在结果中多次包含相同的四元组。
8.返回结果: 最后,函数返回包含所有与目标值相加的唯一四元组的result向量
Code:
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++){
// 剪枝 nums[k] > target 要是负数呢
if (nums[k] > target && nums[k] >= 0) {
break; // 这里使用break,统一通过最后的return返回
}
// 对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[k] + nums[i] >= 0) {
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(vector<int>{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;
}
};
没空写了,2刷补上