代码随想录算法训练营第六天|LeetCode454,383,15,18
LeetCode 454 四数相加II
//对排序无要求所以使用hash表
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
//注意题目中的数组长度都是n
int n = nums1.size();
//能否将四个数组插入到一个数组中 //自己给自己提高难度。。。
//两两数组比较更合适
unordered_map<int,int> res; //key: a+b的数值; value: a+b数值出现的次数
//遍历nums1和nums2数组,计算两个数组元素之和,以及和出现的次数
for(int a : nums1){
for(int b : nums2){
res[a + b]++;
}
}
int sum = 0;
//遍历nums3和nums4数组,查找哈希表中有没有key值是(0 - (c + d))的,如果有,将value值计入sum中
for(int c : nums3){
for(int d : nums4){
if(res.find(0 - (c + d)) != res.end()){
sum += res[0 - (c + d)];
}
}
}
return sum;
}
};
LeetCode 383 赎金信
//使用hash表,因为对排序无要求,并且假设字符串都是小写字母
class Solution {
public:
bool canConstruct(string ransomNote, string magazine) {
//注意:magazine 中的每个字符只能在 ransomNote 中使用一次
//将magazine的字符插入map中
unordered_map<int, int> res;
for(auto &elem : magazine){
res[elem - 'a'] ++;
}
//将ransomNote的字符与res表中的value进行比较
for(auto &elem : ransomNote){
if(res[elem - 'a'] == 0){
return false;
}
else{
res[elem - 'a'] --;
}
}
return true;
}
};
视频讲解链接:无
LeetCode 15 三数之和
//使用双重循环和哈希表,条件很多,很容易写错
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
//注意:答案中不可以包含重复的三元组
//哈希表法可以使用(0 - (a + b))的方法,但在vector中去重三元组非常麻烦
vector<vector<int>> result; //保存三元组结果
//使用set,既可以排序还能去重,但是set不能取下标
//set<int> res(nums.begin(), nums.end()); 不能这样直接去重,假设三元组为[-4,2,2]
//将nums排序
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i++){
if(nums[i] > 0) break;
//做剪枝操作,采用nums[i] == nums[i-1]的操作是防止跳过[-1,-1,2]这样的数据
if(i > 0 && nums[i] == nums[i-1]) continue;
//三元组是不重复的,但单个三元组里可以包含重复的元素
//设置一个哈希表
unordered_set<int> set;
for(int j = i + 1; j < nums.size(); j++){
//做剪枝操作,采用该条件是防止跳过[-4,2,2]这样的数据
if(j > i + 2 && nums[j-2] == nums[j-1] && nums[j-1] == nums[j]) continue;
int c = 0 - (nums[i] + nums[j]);
if(set.find(c) != set.end()){
result.push_back({nums[i], nums[j], c});
set.erase(c);
}
else{
set.insert(nums[j]);
}
}
}
return result;
}
};
//使用双指针,去重难度降低
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
//使用双指针法比哈希表要方便
//一个for循环,从下标0开始,定义left在i+1的位置,right在数组最右的位置
vector<vector<int>> result;
sort(nums.begin(), nums.end());
for(int i = 0; i < nums.size(); i++){
//如果排序后的第一个元素大于0,可以直接跳出循环
if(nums[i] > 0) break;
//去重三元组第一个元素的方法
if(i > 0 && nums[i] == nums[i-1]) continue;
//nums[i] + nums[left] + nums[right] ?= target
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{
result.push_back({nums[i], nums[left], nums[right]});
//此处的去重逻辑 我认为定位了第一个元素nums[i],就可以直接判断nums[left]和nums[right]了
while(left < right && nums[right -1] == nums[right]) right--;
while(left < right && nums[left + 1] == nums[left]) left++;
//right左移,left右移,一个同时的收缩运动
right--;
left++;
}
}
}
return result;
}
};
LeetCode 18 四数之后
//双指针,基础和三数之和一样,因为要求四元组中的元素也各不相同所以更好写一点,别犯傻呗错误
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
//沿用之前三数之和的基础,多一层for循环
//之前三元数组是单个可以存在重复的元素,本题要求元素互不相同
vector<vector<int>> result;
sort(nums.begin(), nums.end());
//第一次遍历
for(int i = 0; i < nums.size(); i++){
//考虑数组是[-4,-3,-2,-1] target = -10
if(nums[i] > target && nums[i] >= 0) break;
//对四元数组的第一个元素nums[i]去重
if(i > 0 && nums[i] == nums[i-1]) continue;
//第二次遍历
for(int j = i + 1; j < nums.size(); j++){
if((nums[i] + nums[j]) > target && (nums[i] + nums[j]) >= 0) break;
//对四元数组的第二个元素nums[j]去重
if(j > i + 1 && nums[j] == nums[j-1]) continue;
//使用left和right
//nums[i] + nums[j] + nums[left] + nums[right] = target
int left = j + 1, right = nums.size() - 1;
while(left < right){
//int left = j + 1, right = nums.size()-1; //error!傻逼错误,怎么写里面了
if((long)nums[i] + nums[j] + nums[left] + nums[right] > target) right--;
else if((long)nums[i] + nums[j] + nums[left] + nums[right] < target) left++;
else{
result.push_back({nums[i], nums[j], nums[left], nums[right]});
//对四元数组的第三个元素,第四个元素去重
while(left < right && nums[right - 1] == nums[right]) right--;
while(left < right && nums[left + 1] == nums[left]) left++;
//left,right同时收缩
left++;
right--;
}
}
}
}
return result;
}
};