【力扣一轮】454.四数之和 && 383.赎金信

454.四数相加

代码随想录链接

力扣链接

思路

暴力解法就是4个for循环,看所有结果出现0,则计数。

更高效是怎么做?for循环减半。为什么能想到这里,注意到它的和是0,(和可以是任何数)这样就相当于两两数组为一对,看其中一对数组中的元素,在另外一对数组中是否出现了相反数。这里的一对说的是A+B或其他组合方式,(不重要,因为都是随机的)

注意题目要求,允许有重复的计算。也就是说如果一对数组中有两个-2,另一对数组中只有一个2,那么计算为0的次数为2。

所以,需要对其中一个计算一个出现次数。(这里我想的是用multi_set也行,直接count就可以。但由于底层实现为红黑树,不是直接的哈希表。所以用unordered_set其实计算速度更快)

问题

回答视频中最后的几个疑问(自己理解)

Q1:为什么会想到用哈希表?

A1:因为仍然是看其中一个元素是否存在于哈希表中,所以用哈希表会方便快捷。

Q2:用哈希表时,应该用什么哈希结构?为什么不用数组,为什么不用set?

A2:因为在存储时,不仅要存储对应的元素,也要存储元素出现的次数,所以用到map。同时,因为无法确定出现元素大小,用数组开辟空间可能会造成浪费。

伪代码

遍历其中两个数组的和值
	将所有结果及出现次数记录进map中
遍历另外两个数组的和值
	对每一个和值取反
	查看每一个和值是否出现在map中
		若出现
			则计数

代码

int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
    unordered_map<int,int> mp;
    int number = 0 ;
    for(int i = 0 ; i < nums1.size() ;i++){
        for(int j = 0 ; j < nums2.size(); j++){
            int onePlusone = nums1[i]+nums2[j];
            //如果当前元素没有存储在集合中,则将元素存储进集合中,否则次数+1
            unordered_map<int,int>::iterator result = mp.find(onePlusone);
            if(result==mp.end()){
                mp.insert(pair<int,int>(onePlusone,1));
            }else{
                result->second+=1;
            }
        }
    }

    //遍历后两个数组
    for(int i = 0 ; i < nums3.size();i++){
        for(int j = 0 ; j < nums4.size() ; j++){
            int minus = -1*(nums3[i]+nums4[j]);
            unordered_map<int,int>::iterator result = mp.find(minus);
            if(mp.find(minus)!=mp.end()){//如果为end,表示没找到
                number += result->second;
            }
        }
    }
    return number;
}

383.赎金信

思路

同样的使用哈希表。也是判断是否出现的问题。

下一个问题,应该用什么数据结构?现在只需要知道单个字母是否在另一个字符串中出现。结合之前的有效字母异位符,数组,set,map,使用数组即可。因为字母的个数是确定的。并且要存储的是magazine的字母元素。

然而以上想法截止到第二句,都没问题,需要注意的是,不是全对应。比如字符串2中有字符串1中没有的字母,此时字母表数组里面也会有元素没出现。所以判断条件需要多一点。

所以最开始我是用map来纠正,现在想想用字母表数组其实也可以。

伪代码

map版本:

初始化map
遍历'magazine'字符串
	如果map中没有字母
		添加进map中
	反之
		map中对应字母数+1
遍历'ransomNote'字符串
	如果没找到或者最后对应字母次数用完为0
		返回false
	反之
		字母对应位置次数--
返回true

字母表数组版本:

初始化字母数组
遍历'magazine'字符串
    字母数组对应次数+1
遍历'ransomNote'字符串
    字母数组对应次数-1
遍历字母数组
    其中任意字母位置小于0
    	则说明不可以,返回false
返回true

代码

map版本:

bool canConstruct(string ransomNote, string magazine) {
        unordered_map<char, int> mp;
        for (int i = 0; i < magazine.size(); i++) {
            unordered_map<char, int>::iterator result = mp.find(magazine[i]);
            if (result == mp.end()) {
                mp.insert(pair<char, int>(magazine[i], 1));
            } else {
                result->second++;
            }
        }
        for (int j = 0; j < ransomNote.size(); j++) {
            unordered_map<char, int>::iterator result = mp.find(ransomNote[j]);
            if (result == mp.end() || result->second ==0 ) { // 没找到
                return false;
            } else { // 找到啦
                result->second--;
            }
        }
        return true;
    }

字母表数组版本:

bool canConstruct(string ransomNote, string magazine) {
        int alpha_bet[26] = {0};
        for (int i = 0; i < magazine.size(); i++) {
            alpha_bet[magazine[i] - 'a']++;
        }
        for (int j = 0; j < ransomNote.size(); j++) {
            alpha_bet[ransomNote[j] - 'a']--;
            if (alpha_bet[ransomNote[j] - 'a'] < 0) {
                return false;
            }
        }
        return true;
    }
  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你的铭称

随缘惜缘不攀缘。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值