[leetCode 丶 20241106] 1865. 找出和为指定值的下标对

原题: 1865.找出和为指定值的下标对


描述:

给你两个整数数组 nums1nums2 ,请你实现一个支持下述两类查询的数据结构:

1.累加 ,将一个正整数加到 nums2 中指定下标对应元素上。
2.计数 ,统计满足 nums1[i] + nums2[j] 等于指定值的下标对 (i, j) 数目(0 <= i < nums1.length 且 0 <= j < nums2.length)。

实现 FindSumPairs 类:

  • FindSumPairs(int[] nums1, int[] nums2) 使用整数数组 nums1nums2 初始化 FindSumPairs 对象。
  • void add(int index, int val)val 加到 nums2[index] 上,即,执行 nums2[index] += val
  • int count(int tot) 返回满足 nums1[i] + nums2[j] == tot 的下标对 (i, j) 数目。

示例 1

输入:
["FindSumPairs", "count", "add", "count", "count", "add", "add", "count"]
[[[1, 1, 2, 2, 2, 3], [1, 4, 5, 2, 5, 4]], [7], [3, 2], [8], [4], [0, 1], [1, 1], [7]]
输出:
[null, 8, null, 2, 1, null, null, 11]

解释:
FindSumPairs findSumPairs = new FindSumPairs([1, 1, 2, 2, 2, 3], [1, 4, 5, 2, 5, 4]);
findSumPairs.count(7); // 返回 8 ; 下标对 (2,2), (3,2), (4,2), (2,4), (3,4), (4,4) 满足 2 + 5 = 7 ,下标对 (> 5,1), (5,5) 满足 3 + 4 = 7
findSumPairs.add(3, 2); // 此时 nums2 = [1,4,5,4,5,4]
findSumPairs.count(8); // 返回 2 ;下标对 (5,2), (5,4) 满足 3 + 5 = 8
findSumPairs.count(4); // 返回 1 ;下标对 (5,0) 满足 3 + 1 = 4
findSumPairs.add(0, 1); // 此时 nums2 = [2,4,5,4,5,4]
findSumPairs.add(1, 1); // 此时 nums2 = [2,5,5,4,5,4]
findSumPairs.count(7); // 返回 11 ;下标对 (2,1), (2,2), (2,4), (3,1), (3,2), (3,4), (4,1), (4,2), (4,4) 满足 2 + 5 = 7 ,下标对 (5,3), (5,5) 满足 3 + 4 = 7

提示

  • 1 <= nums1.length <= 1000
  • 1 <= nums2.length <= 10^5
  • 1 <= nums1[i] <= 10^9
  • 1 <= nums2[i] <= 10^5
  • 0 <= index < nums2.length
  • 1 <= val <= 10^5
  • 1 <= tot <= 10^9
    最多调用 add 和 count 函数各 1000 次

个人版答案

执行用时: 705 ms 执行内存消耗: 102.68 M

class FindSumPairs {

        Map<Integer, List<Integer>> nums1Indexs = new HashMap<>();
        Map<Integer, List<Integer>> nums2Indexs = new HashMap<>();

        int[] n1, n2;

        public FindSumPairs(int[] nums1, int[] nums2) {
            n1 = nums1;
            n2 = nums2;
            for(int i = 0; i < nums1.length; i++){
                List<Integer> indexs1 = nums1Indexs.getOrDefault(nums1[i], new ArrayList<>());
                indexs1.add(i);
                nums1Indexs.put(nums1[i], indexs1);
            }

            for(int i = 0; i < nums2.length; i++){
                List<Integer> indexs2 = nums2Indexs.getOrDefault(nums2[i], new ArrayList<>());
                indexs2.add(i);
                nums2Indexs.put(nums2[i], indexs2);
            }
        }

        public void add(int index, int val) {
            int tmp = n2[index];
            // must
            List<Integer> indexs2 = nums2Indexs.getOrDefault(tmp, new ArrayList<>());
            indexs2.removeIf(x -> x == index);
            if (indexs2.isEmpty()){
                nums2Indexs.remove(tmp);
            }else {
                nums2Indexs.put(tmp, indexs2);
            }
            // add
            int newTmp = tmp + val;
            // swap
            n2[index] = newTmp;
            // may not
            List<Integer> new21 = nums2Indexs.getOrDefault(newTmp, new ArrayList<>());
            new21.add(index);
            nums2Indexs.put(newTmp, new21);
        }

        public int count(int tot) {
            int c = 0;
            for(int i = 0; i < n1.length; i++){
                c += nums2Indexs.getOrDefault(tot - n1[i], new ArrayList<>()).size();
            }
            return c;
        }
    }

/**
 * Your FindSumPairs object will be instantiated and called as such:
 * FindSumPairs obj = new FindSumPairs(nums1, nums2);
 * obj.add(index,val);
 * int param_2 = obj.count(tot);
 */

优秀解法

class FindSumPairs {
    private int[] nums1;
    private int[] nums2;
    private Map<Integer, Integer> map1;
    private Map<Integer, Integer> map2;

    public FindSumPairs(int[] nums1, int[] nums2) {
        this.nums1 = nums1;
        this.nums2 = nums2;
        this.map1 = new HashMap<>();
        this.map2 = new HashMap<>();

        for(int num : this.nums1){
            this.map1.merge(num, 1, Integer::sum);
        }

        for(int num : this.nums2){
            this.map2.merge(num, 1, Integer::sum);
        }
    }
  
    public void add(int index, int val) {
        this.map2.merge(this.nums2[index], -1, Integer::sum);
        this.nums2[index] += val;
        this.map2.merge(this.nums2[index], 1, Integer::sum);
    }
  
    public int count(int tot) {
        int result = 0;
        for(int num : this.nums1){
            if(num >= tot) continue;
            result += this.map2.getOrDefault(tot - num, 0);
        }
        return result;
    }
}

/**
 * Your FindSumPairs object will be instantiated and called as such:
 * FindSumPairs obj = new FindSumPairs(nums1, nums2);
 * obj.add(index,val);
 * int param_2 = obj.count(tot);
 */

个人解题思路与优秀答案解析

题目分析及个人版思路

  1. 计算两个数组所有元素可组成的和的下标对的个数, 那我们易知遍历数组对所有数字求和即可
  2. 分析题目提示, 只有数组nums2会被求和操作, 那我们容易获得思路, 对nums2所有相同元素, 统计下标, 则当求和时候我们使用和-nums1[i]的值去获取之前储存的元素下标数组长度, 求和即可得下标对数量.
  3. 注意题中所需要实现的方法, 当调用add的时候, 操作nums2后, 要重新统计相同元素的下标, 防止求和异常
  4. 详见代码.

进阶版思路
这把我败在了api上...哈哈哈哈哈哈, 我真没用过 map.merge 啊! 这下学到了. 思路是一致的, 看他代码就好