代码随想录算法训练营第七天 | 四数相加、赎金信、三数之和、四数之和

454.四数相加

视频讲解: 学透哈希表,map使用有技巧!LeetCode:454.四数相加II

文章讲解:454.四数相加

之前做过,知道用map,但是太久没用过map,一时间不知道怎么用map,干瞪眼十几分钟,最后看了题解,思路有,但是map的用法限制了我……

unordered_map怎么在算法题中使用

unordered_map是std命名空间下的,所以自己写ACM模式的时候记得加std::

由该图能看出,unordered_map查找的效率最高,但是内部元素无序

适用于:当作记录型变量用于需要多次查找的场合

创建unordered_map

//注意给出两个模板类型变量
unordered_map<type1, type2> map;
//设定初值方法
unordered_map<t1, t2> map = {{key1, value1}, {key2, value2}, ……};
vector<pair<t1, t2>> v = {{key1, value1}, {key2, value2}, ……};  
//使用既有pair数组初始化
unordered_map<int, string> map(v.begin(), v.end());

插入一个元素进map

//如果要记录的是<key, value>
map[key] = value;
//或者复杂点
map.insert(pair<type1, type2>(key, value));
//如果记录key出现几次
map[key]++;//[]被重载过,即使没有key也会创建一个并赋值1

map的迭代器

//使用迭代器访问key和value
unordered_map<int, string> map;
auto it = map.begin();
it->first = key;//it视作一个pair<int, string>元素,用->访问key和value
it->second = value;//说白了就是用first和second

map的增删改查方法

iterator find(const type1& key)    //返回key在map中的位置,没有就指end()
size_t count(const type1& key)    //返回哈希桶中关键码为key的键值对的个数
insert    //插入键值对
erase     //删除键值对

注意erase方法是使用迭代器删除元素,传入的参数指向目标的迭代器,而返回下一个元素的迭代器,用for遍历删除时不要iter++,应该使用iter = map.erase(iter)

代码

class Solution {
public:
    int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
        unordered_map<int, int> map1;
        for(int a : nums1) {
            for(int b : nums2) {
                int sum = a + b;
                map1[sum]++;
            }
        }
        int ans = 0;
        for(int a : nums3) {
            for(int b : nums4) {
                if(map1.count(-a-b)) 
                    ans += map1[-a-b];
            }
        }
        return ans;
    }
};

383.赎金信

Carl文章&视频链接:代码随想录 | 383.赎金信

看覆不覆盖就完了,用char alpha[26]或者开一个map都行,一次遍历++,一次遍历--,缺了就false,不缺就true

代码

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {
        unordered_map<int, int> map;
        for(char c : magazine) {
            map[c]++;
        }
        for(char c : ransomNote) {
            if(map[c]) map[c]--;
            else return false;
        }
        return true;

    }
};

15.三数之和(双指针)

Carl文章&视频链接:代码随想录 | 三数之和

该题看起来是两数之和的拓展,所以自然想到用双指针,但是有3个数,得3个指针,所以拆分子问题,一个指针在大循环里移动,小循环内使用两数之和的方法查找。

还得去重操作,没有关注,WA了几发,哈希做法需要大量剪枝没看。

代码

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        int n = nums.size();
        for(int i = 0;i < n - 2;i++) {
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            int target = -nums[i];
            int left = i + 1, right = n - 1;
            while(left < right) {
                int sum = nums[left] + nums[right];
                if(sum == target) {
                    ans.push_back(vector<int>{nums[i], nums[left], nums[right]});
                    while(left < right && nums[left] == nums[left + 1]) left++;
                    while(right > left && nums[right] == nums[right - 1]) right--;
                    left++;
                    right--;
                }
                else if(sum < target) {
                    left++;
                }
                else 
                    right--;
            }
        }
        return ans;
    }
};

四数之和(双指针)

Carl文章&视频链接:代码随想录 | 四数之和

跟三数之和差不多,继续拆分子问题套循环,不过又多了剪枝操作

还得注意范围,此题会爆int,得用long long

代码

class Solution {
public:
    vector<vector<int>> fourSum(vector<int>& nums, int target) {
        sort(nums.begin(), nums.end());
        vector<vector<int>> ans;
        int n = nums.size();
        
        for(int i = 0;i < n - 3;i++) {
            if(i > 0 && nums[i] == nums[i - 1]) continue;
            if ((long long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {//已经太大
                break;
            }
            if ((long long) nums[i] + nums[n - 3] + nums[n - 2] + nums[n - 1] < target) {//已经太小
                continue;
            }
            for(int j = i + 1;j < n - 2;j++) {
                if(j > i + 1 && nums[j] == nums[j - 1]) continue;
                if ((long long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {//已经太大
                    break;
                }
                if ((long long) nums[i] + nums[j] + nums[n - 2] + nums[n - 1] < target) {//已经太小
                    continue;
                }
                int left = j + 1, right = n - 1;
                while(left < right) {
                    long long sum = (long long)nums[left] + nums[right] + nums[i] + nums[j];
                    if(sum == target) {
                        ans.push_back(vector<int> {nums[i], nums[j], nums[left], nums[right]});
                        while(left < right && nums[left] == nums[left + 1]) left++;
                        while(left < right && nums[right] == nums[right - 1]) right--;
                        left++;
                        right--;
                    }
                    else if(sum > target) {
                        right--;
                    }
                    else 
                        left++;
                }
            }
        }
        return ans;
    }
};
  • 19
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值