羊羊刷题笔记Day07/60 | 第三章 哈希表P2 | 454. 四数相加II、383. 赎金信、15. 三数之和、18. 四数之和

454 四数相加Ⅱ

思路:把两个分成两组,组内的两组合并求和与另一组相比较,如果存在元素则求两个key的笛卡尔积
数据结构:由于数字相加后很大可能为相同的 Set里不存储重复元素 需要用Map计数,因此选用HashMap

代码:

public int fourSumCount(int[] nums1, int[] nums2, int[] nums3, int[] nums4) {
    // 思路:把两个分成两组,组内的两组合并求和与另一组相比较,如果存在元素则求两个key的笛卡尔积
    // 数据结构:为什么使用Map而不用Set - 由于数字相加后很大可能为相同的 Set里不存储重复元素 需要用Map计数

    HashMap<Integer, Integer> hm1 = new HashMap<>();
    for (int i : nums1) {
        for (int i1 : nums2) {
            int sum = i + i1;
            if (hm1.containsKey(sum)) {
                Integer integer = hm1.get(sum);
                hm1.put(sum, ++integer);
            }
            else {
                hm1.put(sum, 1);
            }
        }
    }

    HashMap<Integer, Integer> hm2 = new HashMap<>();
    for (int i : nums3) {
        for (int i1 : nums4) {
            int sum = i + i1;
            if (hm2.containsKey(sum)) {
                Integer integer = hm2.get(sum);
                hm2.put(sum, ++integer);
            }
            else {
                hm2.put(sum, 1);
            }
        }
    }

    int count = 0;
    for (Integer key : hm1.keySet()) {
        if (hm2.containsKey(-key) && hm2.get(-key) != 0) {
            // 求笛卡尔积
            count += hm1.get(key) * hm2.get(-key);
        }
    }

    return count;
}

383 赎金信

数据结构:

  • 题目中:是否由字符构成 - Hash
  • 涉及到重复元素:HashMap

思路:将magazine里字母放进HashMap,由ransomNote去减,都是零则true,否则false

public boolean canConstruct(String ransomNote, String magazine) {
    // 数据结构:
    // 题目中:是否由字符构成 - Hash
    // 涉及到重复元素:HashMap

    // 思路:将magazine里字母放进HashMap,由ransomNote去减,都是零则true,否则false
    // 放进HashMap
    HashMap<Character, Integer> hm = new HashMap<>();
    for (int i = 0; i < magazine.length(); i++) {
        Character key = magazine.charAt(i);
        if (hm.containsKey(key)){
            Integer integer = hm.get(key);
            hm.put(key, ++integer);
        }
        else {
            hm.put(key, 1);
        }
    }

    // 删 - 有就删 - 连对应的字符都没有就false
    for (int i = 0; i < ransomNote.length(); i++) {
        Character key = ransomNote.charAt(i);
        if (hm.containsKey(key)){
            Integer integer = hm.get(key);
            // 没有返回false
            if (integer - 1 < 0){
                return false;
            }
            // 有就删一个
            hm.put(key, --integer);
        }
        // 连记录都没有返回false
        else {
            return false;
        }
    }

    return true;

}

15 三数之和

🔴变化:把所有数都放一个数组里,且要求不重复

  • 都在一个数组 - 双指针
  • 不重复 - 剪枝与去重

自己写:

数据结构:涉及到不容许有重复元素 使用HashMap
思路:把nums元素都存储到HashMap之后,再判断?for判断?复杂度(O2)失去了哈希法的优点

看视频:

🔴难点:

  • 想到三指针法 - 先排序
  • 去重:1.左右指针去重 2.i元素去重

代码:

public List<List<Integer>> threeSum(int[] nums) {
    
    List<List<Integer>> list = new ArrayList<>();
    // 排序
    int[] arr = Arrays.stream(nums).sorted().toArray();

    for (int i = 0; i < arr.length; i++) {
        // 剪枝 - 都是正数
        if (arr[i] > 0) return list;

        // 去重 - i元素
        if (i >0 && arr[i] == arr[i - 1]){
            continue;
        }

        // 定义指针
        int left = 1 + i;
        int right = arr.length - 1;

        
        while (right > left){
            int sum = arr[i] + arr[left] + arr[right];

            if (sum == 0){
                // 获得元素
                list.add(Arrays.asList(arr[i],arr[left],arr[right]));
                // 左右指针去重
                while (right > left && arr[right] == arr[right - 1]) right--;
                while (right > left && arr[left] == arr[left + 1]) left++;

                // 更新位置
                left++;
                right--;
            } else if (sum > 0) {
                // 数变小
                right--;
            }else left++;
        }
    }
    return list;
}

18 四数之和

🔴变化:把所有数都放一个数组里,且要求不重复,数字增加到了四个

  • 都在一个数组 - 双指针
  • 不重复 - 剪枝与去重
  • 数字增加到四个 - 再加多一个指针 嵌套一层循环

🔴思路:在三数之和的基础上嵌套一层循环
🔴难点:剪枝与去重

public List<List<Integer>> fourSum(int[] nums, int target) {
    
    List<List<Integer>> list = new ArrayList<>();
    // 1. 排序数组
    Arrays.sort(nums);

    // 2.结合新元素k的三数之和 - 三数之和再套壳一层循环
    for (int k = 0; k < nums.length; k++) {
        // 判断 - 减枝
        if (nums[k] > target && nums[k] > 0)
            break;

        // 判断 - 去重
        if (k > 0 && nums[k - 1] == nums[k])
            continue;

        for (int i = k + 1; i < nums.length; i++) {
            // 剪枝
            if (nums[k] + nums[i] > target && nums[k] + nums[i] > 0)
                break;

            // 去重 - i移动后与前面元素相同
            if (i > k + 1 && nums[i] == nums[i - 1])
                continue;

            // left 与 right 往内缩
            int left = i + 1;
            int right = nums.length - 1;
            while (right > left) {
                // 获取元素
                long sum = (long) nums[k] + nums[i] + nums[left] + nums[right];
                if (sum == target) {
                    list.add(Arrays.asList(nums[k], nums[i], nums[left], nums[right]));
                    // 去重 - left 与 right 元素相同
                    while (right > left && nums[right] == nums[right - 1]) right--;
                    while (right > left && nums[left] == nums[left + 1]) left++;
                    left++;
                    right--;
                } else if (sum > target) {
                    right--;
                }else left++;
            }
        }
    }
    return list;
}

学习资料:
454 四数相加Ⅱ
383 赎金信
15 三数之和
18 四数之和

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值