2025.3.13---哈希表:四数相加,赎金信,三数之和

一、四数相加||

该题的主要思路是:

如果用四个for循环遍历的话时间复杂度会非常大,所以拆分一下,两个数组一起遍历。具体来说就是先遍历数组12,将12所有元素相加和sum1的情况以及出现的次数记录在map中;然后遍历数组34,也是计算34所有元素的相加和,找出有没有等于-sum1的情况(这样四个数组相加就等于0了),一旦找到一个情况,cnt就等于cnt+map.getValue(sum1)。

class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> map = new HashMap<>();
        int cnt = 0;
        for(int i =0;i<nums1.length;i++){
            for(int j =0;j<nums2.length;j++){
                int sum1 = nums1[i] + nums2[j];
                int value = map.getOrDefault(sum1,0)+1;
                map.put(sum1,value);
            }
        }
        for(int i =0;i<nums3.length;i++){
            for(int j =0;j<nums4.length;j++) {
                int sum2 = nums3[i] + nums4[j];
                if(map.containsKey(-sum2)){
                    cnt = cnt+map.get(-sum2);
                }
            }
        }
        return cnt;
    }
}

二、赎金信 

主要思路:

先遍历ransomNote,将里面的每一个字母以及出现的次数放进一个map集合中,遍历完成后开始遍历magazine,如果 magazine中某一个字母在map中出现,将其对应的出现次数减一,直到出现次数为0就在map中删除该字母,最后遍历完,如果map是空,就说明在magazine中,ransomNote的每一个字母都有。

 public static boolean canConstruct(String ransomNote, String magazine) {
        Map<String,Integer> map = new HashMap<>();
        for (int i = 0; i < ransomNote.length(); i++) {
            String s = ransomNote.substring(i,i+1);
            int cnt1 = map.getOrDefault(s,0)+1;
            map.put(s,cnt1);
        }
        for (int i = 0; i < magazine.length(); i++) {
            String s = magazine.substring(i,i+1);
            if(map.containsKey(s)){
              int cnt = map.get(s)-1;
                  if(cnt == 0){
                     map.remove(s);
               }else{
                     map.put(s,cnt);
               }
            }
        }
        return map.isEmpty();
    }

三、三数之和 

主要有两大难点:

1.如果用哈希表的话,按照之前的思路是,先两个for循环遍历然后求和sum,再一个for遍历,找到符合-sum的数字并添加进去,但是如何去重是个问题,如果添加完之后再判断再去重代码工程量会很大。

为了解决第一个问题,我们可以采用另一种思路---双指针法:先将整个数组进行一个从小到大的排序,再进行一个for循环遍历,将i的右边第一个数字处放一个left指针,将数组最后一个数字放上right指针,然后sum=nums[i]+nums[left]+nums[right],如果sum大于0,那说明大的数字(right)加的太大了,right--(让大的数字小一点);如果sum小于0,那说明小的数字(left)加的太小了,left++(让小的数字大一点);直到等于0,就添加到list中去。

2.怎么去重?

nums[i]的去重只需要,如果nums[i]==nums[i-1],就continute,结束此轮循环判断下一轮循环。(为什么判断条件不是nums[i+1]==nums[i]呢?因为如果判断条件是这个,那么在第i轮时,直接就空过i轮的数据到i+1,但nums[i]==nums[i-1],因为i-1轮的数据已经得到,所以i轮与它相同数字的话空过也没关系了)

nums[left]的去重只需要判断1:left<right 2:nums[left]==nums[left+1] 满足就 left++

nums[right]的去重只需要判断1:left<right 2:nums[right]==nums[right-1] 满足就 right--

left,right指针都是往数组中心靠拢,所以都是往数组中心方向比较。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);//排序
        for(int i=0;i<nums.length;i++){
            if(nums[i]>0) return res;
        //如果排序完第一个数字(最小的数字)大于0,那和就不可能为0
            if(i>0 && nums[i]==nums[i-1]) continue;
        //对nums[i]进行去重
            int left =i+1,right = nums.length-1;
            while(left<right){
                int sum = nums[i]+nums[left]+nums[right];
                if(sum>0){right--;} 
                else if(sum<0) {left++;}
                else {
                res.add(Arrays.asList(nums[i],nums[left],nums[right]));
       //一定要注意将序列添加完之后再去重
                while(left<right && nums[right]==nums[right-1]) right--;
                while(left<right && nums[left]==nums[left+1]) left++;
       //注意这里用while
                right--;
                left++;
                }
            }
        }
        return res;
    }
}

以上来源于代码随想录 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值