哈希表 part02:454.四数相加II,383. 赎金信,15. 三数之和*,18. 四数之和*

454.四数相加II

题目

在这里插入图片描述
题意:nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0,与四数之和区分。

解题方法(map)

流程:
1、遍历A、B
2、umap的key存放a+b之和(涉及到查找),value存放a+b之和出现的次数
3、遍历C、D
4、使用map.find查找(0-c-d),如果找到了,次数count加上对应的value

难点(想不到如何处理4个数)

  • 巧妙:把四数相加变成了两数相加
  • 为什么用map:除了key,还需要用value存a+b之和出现的次数
  • 巧妙:umap[a+b]++;

key(索引)存a+b之和,value(能修改的值)是a+b之和出现的次数

  • 犯错:以为会漏算,其实不会(因为遍历了C、D,只要符合情况都会加上)

例如:(c+d)出现了3次,(a+b)出现了4次,实际上count会在三轮不同的循环中+4+4+4

代码

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]++;//巧妙:key是a+b数值,value是a+b出现的次数
            }
        }
        int count = 0;//要输出的数量
        int find_num = 0;//要查找的数值
        for(int c:nums3){
            for(int d:nums4){
                find_num = 0-(c+d);
                if(umap.find(find_num) != umap.end()){
                    count+=umap[find_num];
                }
            }
        }
        return count;
    }
};

383. 赎金信

题目

在这里插入图片描述

思考历程

类似 242.有效的字母异位词

解题方法(数组)

  • 题目关键:不可重复使用、只有小写字母
  • 核心:涉及到26个小写字母,使用数组建立哈希关系(数组下标为各字母,数组内容为字母出现次数)
  • 流程:
    1、magazine往数组里加次数
    2、ransomNote往数组里减次数
    3、只要出现次数小于0说明false了

难点

感悟:什么时候用数组建立哈希关系

像只有26个小写字母这种少量、连续的数据时使用数组。数组下标充当key,数组内容充当value。key是可以直接当索引被查找的,value的内容是我们可以修改的。

  • record[magazine[i] - 'a']++;中,数组下标[magazine[i] - 'a']代表某一个小写字母,++可以修改该位置的value

代码

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        int record[26]={0};//怎么知道是数组还是数组元素呢
        //magazine往里加
        for(int i=0;i<magazine.size();i++){
            record[magazine[i] - 'a']++;
        }
        //ransomNote往里减(因为只能使用一次),遇到负数说明失败了
        for(int j=0;j<ransomNote.size();j++){
            record[ransomNote[j] - 'a']--;
            if(record[ransomNote[j] - 'a']<0){
                return false;
            }
        }
        return true;
    }
};

15. 三数之和

题目

在这里插入图片描述
重复的三元组:
[-1, 0, 1]与[1, -1, 0]与[0, -1, 1]等,本题先排序,然后对a、b、c用不同的方法去重

思考历程

  1. 知道重复的三元组是什么意思(答案如上所示)
  2. 不知道和四数相加题目有什么区别(本题是1个数组内部找3个数相加,需要考虑重复情况;四数相加题目是4个独立数组分别找1个数出来相加,不用考虑重复情况)

解题方法(双指针法)

核心:a+b+c=0

令遍历变量i=a,b从i+1位置开始,c从数组末尾开始,寻找当前a合适的(a,b,c)

解题流程:

  1. 对a去重:nums[i]不能等于nums[i-1],前者三元组的集合是后者的真子集
  2. 收获第一个结果
  3. 对b去重:nums[left]不能等于nums[left+1],若等,left+1,
  4. 对c去重:nums[right]不能等于nums[right-1],若等,right-1
  5. left右移,right左移,缩小范围

难点(abc的去重)

  1. 如何分配abc,三者如何去重

在这里插入图片描述

  1. 犯错:漏了第一处的while(right>left),这是一个循环,直到left与right相遇,本i的任务才结束
  2. 漏了第二处的while(right>left),因为left与right已改变,所以需要重新判断
  3. 去重后还需left++; right–;原因是去重后,nums[left]的值与收获结果时nums[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++){//遍历变量i即a
            if(nums[i]>0){
                return result;
            }
            if(i>0 && nums[i] == nums[i-1]){//对a去重
                continue;                        
            }
            int left = i+1;//b出现
            int right = nums.size()-1;//c出现
            while(right>left){
                if(nums[i]+nums[left]+nums[right]>0) right--;
                else if(nums[i]+nums[left]+nums[right]<0) left++;
                else{//a+b+c=0 找到一个结果了
                    result.push_back(vector<int>{nums[i],nums[left],nums[right]});
                    while(right > left && nums[left]==nums[left+1]) left++;//对b去重
                    while(right > left && nums[right]==nums[right-1]) right--;//对c去重

                    //找到答案时,双指针同时收缩
                    left++;
                    right--;
                }
            }
        }
        return result;
    }
};

18. 四数之和

题目

思考历程

解题方法

难点

代码

在这里插入代码片
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值