代码随想录刷题day07hashmap最难部分居然是用双指针???

  • 代码随想录刷题day07

    力扣454. 四数相加 II

    链接: https://leetcode.cn/problems/4sum-ii/

    问题描述

    给你四个整数数组 nums1、nums2、nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:

    0 <= i, j, k, l < n
    nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

    在这里插入图片描述

    代码实现

    class Solution {
        public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
    
            //构建hashmap来存储前面两个数组nums1和nums2里面的和的元素,包括他们出现的次数
            HashMap<Integer,Integer> map = new HashMap<>();
            //用sum来表示数组1和数组2之和的临时介质
            int sum1;
            int sum2;
            int result = 0;
    
            //先用hashmap存储数组1和数组2和的所有可能
            for(int i : nums1){
                for(int j : nums2){
                    sum1 = i + j;
                    //将和存储进入到hashmap中
                    if(map.containsKey(sum1)){
                        //将value中存储的该和次数加1
                        map.put(sum1,map.get(sum1) + 1);
                    }else{
                        //如果map中不存在,添加一次这个元素
                        map.put(sum1,1);
                    }
                }
            }
    
            //求出3,4数组的和,看看和数组1,2的和是否构成和为0
            for(int i : nums3){
                for(int j : nums4){
                    sum2 = i + j;
    
                    if(map.containsKey(0 - sum2)){
                        result += map.get(0 - sum2);
                    }
                }
            }
            return result;
    
    
        }
    }
    

    c++ 版本

    class Solution {
    public:
        int fourSumCount(vector<int>& nums1, vector<int>& nums2, vector<int>& nums3, vector<int>& nums4) {
            //使用key存储两数之和,使用value存储两数之和出现的次数
            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;
        }
    };
    

    注意点

  • 前面的两个数组之和存储到hashMap中去,接下来只需要检验的是后两个数组之和 == (0 - 前两个数组之和)

力扣383. 赎金信

链接: https://leetcode.cn/problems/ransom-note/

题目描述

给你两个字符串:ransomNote 和 magazine ,判断 ransomNote 能不能由 magazine 里面的字符构成。

如果可以,返回 true ;否则返回 false 。

magazine 中的每个字符只能在 ransomNote 中使用一次。

在这里插入图片描述

代码实现

class Solution {
public:
    bool canConstruct(string ransomNote, string magazine) {

        int record[26] = {0};

        //如果说赎金信字符长度大于magazine的长度,肯定有不满足的情况
        if(ransomNote.size() > magazine.size()){
            return false;
        }
        //通过hash数组来实现
        for(int i = 0 ; i < magazine.length();i++){
            //record数组来存储magazine中每个字母的出现次数
            record[magazine[i] - 'a']++; 
        }
        for(int j = 0 ;j < ransomNote.length();j++){
            //数组magazine中的元素出现次数-数组ransomNote中元素出现次数
            record[ransomNote[j] - 'a']--;
            //如果说中间出现了小于0的个数,说明magazine中的元素不够用
            if(record[ransomNote[j] - 'a'] < 0){
                return false;
            } 
        }
        //只需要record的每个元素都大于0就可以满足题目的需求
        return true;
    }
};

注意点

  • 需求的是ransomNote被magazine里面的元素完美覆盖,所以建造的哈希表需要记录的次数是magazine - ransomNote中的元素次数 > 0

力扣15. 三数之和

链接: https://leetcode.cn/problems/3sum/

问题描述

给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请

你返回所有和为 0 且不重复的三元组。

注意:答案中不可以包含重复的三元组。
在这里插入图片描述

代码实现

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {

        //本题采用的是双指针法
        vector<vector<int>> result;
        //对题目中的整数数组先进行排序
        sort(nums.begin(),nums.end());

        //找出a + b + c = 0
        //a = nums[i], b = nums[left], c = nums[right]
        for(int i = 0;i < nums.size();i++){
            //如果排序后的数组第一个元素>0,不可能和 = 0;
            if(nums[i] > 0){
                return result;
            }
            //对第一个a进行去重
            if( i > 0 && nums[i] == nums[i - 1]){
                continue;
            }//如果i和后面的i元素相同,就可以直接将i向后移动,用后面一个i
            int left = i + 1;
            int right = nums.size() - 1;
            //left如果等于right,就应该截止了,因为这样会导致最终的结果b = c
            while(left < right){
                if(nums[i] + nums[left] + nums[right] < 0){
                    //说明整体和较小,需要扩大其中的元素
                    left++;
                }else if(nums[i] + nums[left] + nums[right] > 0){
                    right--;
                }else{
                    //输出当前的结果
                    result.push_back(vector<int>{nums[i],nums[left],nums[right]});
                    //出现了满足情况的解法,开始准备去排除重复b,重复c
                    while(left < right && nums[right] == nums[right -1]){
                        right--;
                    }
                    while(left < right && nums[left] == nums[left + 1]){
                        left++;
                    }
                    //完成了去重b和c,双指针开始收缩,查看是否存在其他的解法
                    right--;
                    left++;
                }

            }


        }
        return result;

    }
};

注意点

  • 减枝的判断

  • 不适用hashmap的原因是hashmap对于查找{0,0,0}这种类似的解不适合

力扣 18. 四数之和

链接:https://leetcode.cn/problems/4sum/

问题描述

给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):

  • 0 <= a, b, c, d < n
  • abcd 互不相同
  • nums[a] + nums[b] + nums[c] + nums[d] == target

你可以按 任意顺序 返回答案 。
在这里插入图片描述

代码实现

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,后面统一使用return 返回
                break;
            }
            //第一重减枝中先对nums[k]去重
            if(k > 0 && nums[k] == nums[k - 1]){
                continue;
                //向下一个k
            }
            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]});
                        //找到结果的情况下对left和right去重,查找下一个结果
                        while(left < right && nums[right] == nums[right - 1]){
                            right--;
                        }
                        while(left < right && nums[left] == nums[left + 1]){
                            left++;
                        }
                        //找到答案,双指针同时收缩
                        right--;
                        left++;

                    }
                }

            }

        }
        return result;

    }
};

注意点

  • 一重减枝和二重剪枝的判断都是向外部
  • 最后判断是向内部
HashMap和ConcurrentHashMap的区别有以下几点: 1. 线程安全性:HashMap是非线程安全的,因为在多线程环境下,多个线程可能同时对HashMap进行写操作导致数据错误。而ConcurrentHashMap是线程安全的,内部通过分段锁的机制保证了多线程环境下的安全性。 2. 效率:在单线程环境下,HashMap的效率要优于ConcurrentHashMap。因为ConcurrentHashMap需要做额外的安全措施,例如锁的申请和释放等操作,会带来额外的开销。而在多线程环境下,ConcurrentHashMap由于采用了分段锁的机制,可以进行高效的并发访问,所以效率会优于HashMap。 3. 迭代器:HashMap的迭代器是fail-fast的,即如果在迭代过程中对HashMap进行写操作,会直接抛出ConcurrentModificationException异常。而ConcurrentHashMap的迭代器是弱一致性的,即当迭代的过程中对ConcurrentHashMap进行修改,迭代器仅仅是不保证是否看到了修改,但是不会抛出ConcurrentModificationException异常。 4. 初始容量和负载因子:HashMap的初始容量为16,负载因子为0.75。而ConcurrentHashMap可以通过设置segment水平的并发度来提高并发访问能力,其默认的segment大小为16,而每个segment的初始化容量和负载因子也是由用户可设置的。 5. 线程安全级别:ConcurrentHashMap提供了多种不同的线程安全级别,可以根据具体业务场景选择不同的级别进行使用。常用的级别包括:完全并发(最高级别)、读写分离(默认级别)、只读等级(最低级别)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值