454.四数相加
class Solution {
public:
int fourSumCount(vector<int>& nums1, vector<int>& nums2,
vector<int>& nums3, vector<int>& nums4) {
unordered_map<int,int>umap;
for(int a : nums1){
for(int b : nums2){
umap[a+b]++;
}
}
int count = 0;
for(int c : nums3){
for(int d : nums4){
if (umap.find(0 - (c + d)) != umap.end()) {
count += umap[0 - (c + d)];
}
}
}
return count;
}
};
这道题虽然是四数相加,但是我们可以两两比较化简为两数相加
先定义unordered_map,key放a+b的和,value放次数
然后定义count技术
再把 0-(c+d)的和与key比较,如果找到了那么 就用count把map中key对应的value也就是出现次数统计出来。
383.赎金信
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 i = 0;i < ransomNote.size(); i ++){
record[ransomNote[i] - 'a'] -- ;
if(record[ransomNote[i] - 'a'] < 0)
return false;
}
return true;
}
};
在本题的情况下,使用map的空间消耗要比数组大一些的,因为map要维护红黑树或者哈希表,而且还要做哈希函数,是费时的!数据量大的话就能体现出来差别了。 所以数组更加简单直接有效!
只要发现有负数说明有至少一个字母不在magazine里,输出false即可
15.三数之和
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--;
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++;
left++;
right--;
}
}
}
return result;
}
};
用set把符合条件的三元组放进vector中,然后再去重,这样是非常费时的,很容易超时,去重的过程不好处理,有很多小细节,如果在面试中很难想到位。
这里用双指针法,首先将数组排序,然后有一层for循环,i从下标0的地方开始,同时定一个下标left 定义在i+1的位置上,定义下标right 在数组结尾的位置上。a相当于i,b相当于left,c相当于right。
当第一个数大于0则不存在,然后去重。
if (nums[i] == nums[i + 1]) {
continue;
}
若使用这种去重会漏掉 -1,-1 ,2这种情况
当三数之和大于0,说明大了,right向左
当三数之和小于0,说明小了,left向右
对三元组去重应该在找到三元组之后
最后 left++;right--
18.四数之和
https://leetcode.cn/problems/4sum/
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(left < right){
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;
}
};
与三数之和类似,多加了剪枝和多了一次for循环
四数之和的双指针解法是两层for循环nums[k] + nums[i]为确定值,依然是循环内有left和right下标作为双指针,找出nums[k] + nums[i] + nums[left] + nums[right] == target的情况,三数之和的时间复杂度是O(n^2),四数之和的时间复杂度是O(n^3) 。