代码随想录第7天 |● 454.四数相加II●383. 赎金信●15. 三数之和●18. 四数之和●哈希表总结

题目:454.四数相加Ⅱ

思路:

0.知道用map,但是map存啥
1.暴力法,四层循环遍历哈哈哈哈
2.分而治之,化繁为简,四个数组a,b,c,d分成两组,题目求符合要求的元祖个数,所以将a+b的值和出现次数存储,之后遍历查找c+d中0-(c+d)出现的次数,统计为结果
时间复杂度: O(n^2)
空间复杂度: O(n^2),最坏情况下A和B的值各不相同,相加产生的数字个数为 n^2

坑:

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int,int> map;
        for(int i=0;i<nums1.size();i++){
            for(int j=0; j<nums2.size();j++){
                int sum=nums1[i]+nums2[j];
                auto iter=map.find(sum);
                if(iter!=map.end()){
                    (iter->second)++;
                }else{
                     map.insert({sum,1});
                }
            }
        }
        //可优化为 范围for循环和 map[a+b]++;  
        //下标索引机制,使用下标访问不存在的元素时,会导致向map中添加该下标所对应的新元素``
        int count=0;
        for(int i=0;i<nums3.size();i++){
            for(int j=0; j<nums4.size();j++){
                int sum=nums3[i]+nums4[j];
                if(map.find(0-sum)!=map.end()){
                    count+=map[0-sum];
                }
            }
        }
        return count;
    }
};

补充:

map的操作

插入、查找、删除,遍历
插入
map<int,int> map

  1. pair
    map.insert(pair<int,int>(1,2));
  2. make_pair
    map.insert(make_pair<int,int>(1,3));
  3. value_type
    map.insert(map<int,int>::value_type(2,3));
  4. []
    map[3]=4 ; //插入key为3,value为4

在map中使用下标访问不存在的元素将导致在map容器中添加一个新的元素。

题目:383.赎金信

思路:

1.哈希数组,存储字符串中每个字母出现的次数,遍历第二个字符串时,--,如果有数组中有<0,则不能构成。
2.暴力法,

坑:

  1. 数组初始化错了
class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        //string 可以使用下标访问和范围for循环
        //缺少 判断两个字符串长度,大于直接false
        if(ransomNote.size()>magazine.size())
            return false;
        int table[26]={0};  //报错,初始化{26,0}不对。
        for(auto m:magazine){
            table[m-'a']++;
        }
        for(auto r: ransomNote){
            table[r-'a']--;
            if(table[r-'a']<0)
                return false;
        }
       
       
        return true;
    }
};

补充:

string

访问string对象中的每一个元素
一个string对象表示一个字符序列,可以使用 范围for循环,
访问string对象中的单个字符

  1. 使用下标
  2. 使用迭代器

题目:15.三数之和

思路:

0.类似四数相加,分组为a+b和c,查找0-(a+b),使用两个map存储,一个存a,b ,一个存c,b 需要去重 看错了,是同一个数组内

  1. 暴力法 三层循环
  2. 哈希法,但是去重困难
  3. 三指针法,0,left,right、对应值相加,大了左移right,小了右移left 。难点也是去重 ,先排序就容易,因为目没要求返回下标,可以改变元素的位置

坑:

  1. 依次判断a ,b,c的重复问题,b和c 的重复问题在sum==0时再判断
  2. 重复多,指针需移动多次,使用while 不是if
  3. 这组数符合条件,且与移动的下一个位置不重复,所以left和right都移动
class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end()); // 升序 方便去重
        vector<vector<int>> result;     // 二维数组,存结果
        if ( nums.size() < 3||nums.front()>0||nums.back()<0) {
            return result;
        } else {
            for (int i = 0; i < nums.size() - 2; i++) {
                if(nums[i]>0)
                    break;
                if (i > 0 && (nums[i] == nums[i - 1])) // a去重
                    continue;
                int left = i + 1;
                int right = nums.size()- 1;
                while (left < right) {
                    int sum = nums[i] + nums[left] + nums[right];
                    if (sum > 0) {
                        right--;
                    } else if (sum < 0) {
                        left++;
                    } else  { // sum==0 符合要求再考虑 b c的去重问题
                        result.push_back({nums[i], nums[left], nums[right]});
                        while (left < right &&nums[left] == nums[left +1]) { 
                            // 不是if  是While指针要移动到不重复的位置
                            left++;
                        }
                        while (left < right && nums[right] == nums[right - 1]) {
                            right--;
                        }
                        //超出内存 这组数符合条件,且与移动的下一个位置不重复,所以left和right都移动
                        left++;
                        right--;
                    }
                }
            }
            return result;
        }
    }
};

补充:

sort排序
头文件#include
sort (begin,end,cmp); //cmp可省略,默认升序,cmp可自定义
升序:sort(begin,end,less())
降序:sort(begin,end,greater())
vectort插入二维数组
v.insert({2,3,4});

题目:18.四数之和

思路:

和三数之和相同,指针,but还是双指针 不是多加一个指针,是在套一层循环
注意,目标为target 可正可负,

坑:

  1. 第2级剪枝处理后的break;语句换成return result;会导致返回的结果有缺失
  2. 数据溢出,int改为long,计算是也是long
class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> result;
        if (nums.size() < 4)
            return result;
        for (int i = 0; i < nums.size()-3; i++) {
            if (nums[i] > target && target > 0)
                return result;
            if(i>0&&nums[i]==nums[i-1])  //a去重
                continue;
            for(int k=i+1;k<nums.size()-2;k++){
                if(nums[i]+nums[k]>target&&nums[i]+nums[k]>=0)
                    break;
                //第2级剪枝处理后的break;语句换成return result;会导致返回的结果有缺失
                if(k>i+1&&nums[k]==nums[k-1])  //b去重
                    continue;
                int left=k+1;
                int right=nums.size()-1;
                while(left<right){
                    //报错 数据溢出 ,int改long
                    long sum=(long)nums[i]+nums[k]+nums[left]+nums[right];
                    if(sum>target){
                        right--;
                    }else if(sum<target ){
                        left++;
                    }else {
                        result.push_back({nums[i],nums[k],nums[left],nums[right]});
                        while(left<right&&nums[left]==nums[left+1]){
                            left++;
                        }
                        while(left<right&&nums[right]==nums[right-1]){
                            right--;
                        }
                        left++;
                        right--;
                    }
                }
            }
        }
        return result;
    }
};

哈希总结

一般来说哈希表都是用来快速判断一个元素是否出现集合里

三种常见哈希结构
根据情况分析适用哪种

双指针去重

posted @ 2024-06-13 20:48  跳圈  阅读(14)  评论(0)    收藏  举报