代码随想录算法训练营第七天_哈希表 _ 454.四数相加II 、383. 赎金信 、15. 三数之和、18. 四数之和。

学习目标:

60天训练营打卡计划!

要判断一个元素是否出现在一个集合中,就要使用哈希表!

学习内容:

454.四数相加II

  • 使用空间换时间的策略,将四个数组求和为两个数组。
  • 要加强对map的熟悉。
  • map用于记录相同的结果共出现了几次。
class Solution {
    public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
        Map<Integer,Integer> map = new HashMap();
        int size = nums1.length;
        int sum1 = 0;
        int sum2 = 0;
        int res = 0;

        for(int i = 0; i < size; i++){
            for(int j = 0; j < size; j++){
                sum1 = nums1[i]+nums2[j];
                if(map.containsKey(sum1))
                    map.put(sum1,map.get(sum1)+1);
                else
                    map.put(sum1,1);
            }
        }
        for(int i = 0; i < size; i++){
            for(int j = 0; j < size; j++){
                sum2 = nums3[i]+nums4[j];
                if(map.containsKey(0-sum2))
                    res += map.get(0-sum2);
            }
        }
        return res;
    }
}

383. 赎金信

  • 与242.有效的字母异位词思路相似。
class Solution {
    public boolean canConstruct(String ransomNote, String magazine) {
        int r = ransomNote.length();
        int m = magazine.length();
        int[] tmp = new int[26];
        if(r > m){
            return false;
        }

        for(int i = 0; i < m; i++){
            tmp[magazine.charAt(i)-'a']++;
        }

        for(int j = 0; j < r; j++){
            tmp[ransomNote.charAt(j)-'a']--;
            if(tmp[ransomNote.charAt(j)-'a'] < 0){
                return false;
            }
        }
        return true;
    }
}

15. 三数之和

Java中二维数组操作:

  • 创建: List<List> result = new ArrayList<>();
  • 添加一个一维数组:result.add(Arrays.asList(nums[i], nums[left], nums[right]));

实现:

  • 使用双指针法,在操作之前一定要排序
    • 难点:要对返回的二维数组进行去重操作,可分为两步。
      第一步:先对第一个元素(代号a)nums[i]进行去重 – i > 0 && nums[i] == nums[i - 1]
      并在i到nums.length之间使用双指针法,找到剩下的b和c。
      第二步:找到第一个三元组后要对双指针两侧的数进行去重操作 – right > left && nums[right] == nums[right - 1] 和 right > left && nums[left] == nums[left + 1]
      判断时:right-1 和left+1是为了防止下标越界。
class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);
        int size = nums.length;
        int total = 0;
        int left = 0;
        int right = size - 1;

        for(int i = 0; i < size-2; i++){
            // 当遍历的第一个元素大于0时,
            // 后续的其他组合一定没有符合结果的值了
            if(nums[i] > 0)   return res;

            // a元素的去重操作
            // 如果i++的话,会漏掉连续多个相同值的情况
            if(i > 0 && nums[i] == nums[i-1])  continue;

            left = i + 1;
            right = size - 1;

            while(left < right){
                total = nums[i] + nums[left] + nums[right];
                if(total > 0)  right--;
                else if(total < 0)   left++;
                else{
                    res.add(Arrays.asList(nums[i] ,nums[left] ,nums[right]));
                    // 对元素b去重
                    while(left < right && nums[left] == nums[left+1])  left++;
                    // 对元素c去重
                    while(left < right && nums[right] == nums[right-1])  right--;
                    right--;
                    left++;
                }
            }
        }

        return res;
    }
}

18. 四数之和

  • 基本逻辑都是相似的,将时间复杂度降低一次方。
  • 先排序!
  • 再通过对第一个值判断来进行剪枝操作,后进行第一次去重。
  • 再进行第二次去重,使用continue,防止此次自增后的值缺少相应的去重
  • 找到第一个四元组时进行第三次去重。
class Solution {
    public List<List<Integer>> fourSum(int[] nums, int target) {
        int size = nums.length;
        int left = 0;
        int right = 0;
        int sum = 0;
        List<List<Integer>> res = new ArrayList<>();
        Arrays.sort(nums);

        for(int i = 0; i < size; i++){
            if(nums[i] > 0 && nums[i] > target){
                // 负数求和会变小!
                break;
            }
            // 将重复的组合仅保留一次
            if(i > 0 && nums[i] == nums[i - 1]){
                continue;
                // i++  会缺少一次对i进行上述if判断
            }
            for(int j = i + 1; j < size; j++){
            	// 将重复的组合仅保留一次
                if(j > i + 1 && nums[j] == nums[j - 1]){
                    continue;
                    // j++  会缺少一次对j进行上述if判断
                }
                left = j + 1;
                right = size - 1;
                while(left < right){
                    sum = nums[i] + nums[j] + nums[left] + nums[right];
                    if(sum > target){
                        right--;
                    }
                    else if(sum < target){
                        left++;
                    }
                    else{
                        res.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
                        while(left < right && nums[left] == nums[left + 1]) left++;
                        while(right > left && nums[right] == nums[right - 1]) right--;
                        left++;
                        right--;
                    }
                }
            }
        }
        return res;
    }
}

学习时间:

  • 上午三小时,下午一小时(四数相加),整理文档半小时
  • 12月12日复习,15和18题需要继续熟悉。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值