Leetcode 454.四数相加II
题目链接:454.四数相加II
思路:通过哈希表记录a+b,并在哈希表找寻0 - (c+d) 是否等于 a + b,那么就可以找到四数相加的答案(i, j, k, l),这题于四数之和的区别在于因为它没有要求去重。所以可以用哈希法来做
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
unordered_map<int, int> map;
int count = 0;
for(int a : nums1) {
for(int b : nums2) {
map[a+b]++;
}
}
for(int c : nums3) {
for(int d : nums4) {
auto iter = map.find(0 - (c + d));
if(iter != map.end()) {
count += iter->second;
}
}
}
return count;
}
};
- 时间复杂度为O(n^2)
- 空间复杂度为O(n^2)
Leetcode 383.赎金信
题目链接:383.赎金信
哈希法(map)思路:这题与有效字母异位词有点类似,但我这里使用了map来写,记录magazine的字符++,然后ransomNote的字符–,如果在map中没出现该字符或该字符< 0就return false,否则return true
哈希法(数组)思路:用数组做的话就完全类似于有效字母异位词了。详细思路可以看有效字母异位词
哈希法(map):
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
unordered_map<char, int> map;
for(char x : magazine) {
map[x]++;
}
for(char x : ransomNote) {
auto iter = map.find(x);
if(iter != map.end() && iter->second > 0) {
iter->second --;
} else {
return false;
}
}
return true;
}
};
- 时间复杂度为O(n)
- 空间复杂度为O(n)
哈希法(数组):
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
int record[26] = { 0 };
for(int i = 0; i < ransomNote.size(); i++) {
record[ransomNote[i] - 'a'] --;
}
for(int i = 0; i < magazine.size(); i++) {
record[magazine[i] - 'a'] ++;
}
for(int i = 0; i < 26; i++) {
if(record[i] < 0) return false;
}
return true;
}
};
- 时间复杂度为O(n)
- 空间复杂度为O(1)
Leetcode.15三数之和
题目链接:15.三数之和
思路:这题用哈希法来做的话,不容易达到bugfree。因此这里只写双指针的方法,首先对nums进行排序,这样的话数组就会变成有序,那么对后序去找到target也比较容易。
我们对数组有三个大概的变量,一个是i,一个是left,一个right,i从头开始循环,而left则是i + 1,right 是nums.size() - 1,那主要移动的是left和right,而i由for循环来推进。首先如果我们三数之和是要等于0,如果排序后的数组的第一个元素已经是大于0,那不可能找出合适的三元组,直接return即可。那该如何移动left和right呢,那我们可以用一个循环,当三数之和相加 > 0说明,我们该减少这个数,那right = right - 1即可,那如果 < 0 说明,我们该增大这个数,那left = left + 1即可。等于0的话我们就将这个三元组push到result当中去。然后我们再对right和left进行去重,再移动left和right指针。
双指针法:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i++) {
if(nums[i] > 0) return result;
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 = right - 1;
} else if(nums[i] + nums[left] + nums[right] < 0) {
left = left + 1;
} 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++;
left ++;
right --;
}
}
}
return result;
}
};
- 时间复杂度为O(n^2)
- 空间复杂度为O(1)
Leetcode 18.四数之和
题目链接:18.四数之和
思路:这题也是用哈希法不太好做的,那这里使用双指针法,但这题的思路可以在三数之和的思路上做。那我们前面也是先将数组排序,然后我们增加一个k的循环不变量,两层循环nums[k] + nums[i]作为确定值,循环内有left和right的双指针,从而找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况。额外的就是剪枝的情况,不再像三数之和那么简单了,因为有可能有负数的情况,那么必须nums[k] > target && nums[k] >= 0再可以进行剪枝,在for i循环中则是nums[k] + nums[i] > target && nums[k] + nums[i] >= 0 才能剪枝(有可能出现-4 -3 -2 -1 target = -10,如果简简单单nums[k] > 0 或者是nums[k] + nums[i]就进行剪枝,就会出现找不到target的情况),而去重操作是和三数之和类似的。
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;
}
//去重
if(k > 0 && nums[k] == nums[k - 1]) continue;
for(int i = k + 1; i < nums.size(); i++) {
if(nums[k] + nums[i] > target && nums[k] + nums[i] >= 0) break;
if(i > k + 1 && nums[i] == nums[i - 1]) continue;
int left = i + 1;
int right = nums.size() - 1;
while(right > left) {
if((long) nums[k] + nums[i] + nums[left] + nums[right] > target) {
right --;
} 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]});
while(right > left && nums[right] == nums[right - 1]) right--;
while(right > left && nums[left] == nums[left + 1]) left ++;
right --;
left ++;
}
}
}
}
return result;
}
};
- 时间复杂度为O(n^3)
- 空间复杂度为O(1)
今日收获:温故知新,明天该进入字符串章节了
学习时长:两个半小时