3132.找出与数组相加的整数 II

目标

给你两个整数数组 nums1 和 nums2。

从 nums1 中移除两个元素,并且所有其他元素都与变量 x 所表示的整数相加。如果 x 为负数,则表现为元素值的减少。

执行上述操作后,nums1 和 nums2 相等 。当两个数组中包含相同的整数,并且这些整数出现的频次相同时,两个数组 相等 。

返回能够实现数组相等的 最小 整数 x 。

示例 1:

输入:nums1 = [4,20,16,12,8], nums2 = [14,18,10]
输出:-2
解释:移除 nums1 中下标为 [0,4] 的两个元素,并且每个元素与 -2 相加后,nums1 变为 [18,14,10] ,与 nums2 相等。

示例 2:

输入:nums1 = [3,5,5,3], nums2 = [7,7]
输出:2
解释: 移除 nums1 中下标为 [0,3] 的两个元素,并且每个元素与 2 相加后,nums1 变为 [7,7] ,与 nums2 相等。

说明:

  • 3 <= nums1.length <= 200
  • nums2.length == nums1.length - 2
  • 0 <= nums1[i], nums2[i] <= 1000
  • 测试用例以这样的方式生成:存在一个整数 x,nums1 中的每个元素都与 x 相加后,再移除两个元素,nums1 可以与 nums2 相等。

思路

这与找出与数组相加的整数 I类似,只不过需要删除nums1中的两个元素,这样x就可能存在多个值,取其中最小的。

最简单的想法是将这两个数组排序,枚举 nums1 长度为 2 的子序列组合,将其从数组中删去,判断对应位置上的 nums2[i] - nums1[i] 的值是否都等于 x。如果相等则保存,枚举完所有子序列组合后取保存的最小值即可。排序的时间复杂度为 O(nlogn) 代入 n = 200 大约 460.2,子序列可能的组合有 C(200, 2) = 19900,针对每种组合都要遍历数组,循环 200 次,大概需要执行 200 * 19900 ≈ 4 * 10^6 次,应该不会超时。

可以将 nums2nums1 中的元素两两相减然后统计差值的出现次数,如果出现次数小于 nums2.length 那么该差值一定不是 x。因为 nums1.length - 2 == nums2.length,如果 x 存在,那么其出现次数最少为nums2.length。例如,[1,2,3,4][3,4] 的差值 2 1 0 -1 3 2 1 0 2出现了2次,1出现了2次,0出现了2次,取最小的0。

得到了可能的 x 之后,我们需要判断是否合法,例如 [9,9,1,1,1][5,5,5], 差值 -4 出现了 6 次,4 出现了 9 次。但是 -4 是不合法的,因为使用 nums2 - (-4) 还原回去的个数对不上。

看官网题解 // todo

代码

/**
 * @date 2024-08-09 0:30
 */
public class MinimumAddedInteger3132 {

    public int minimumAddedInteger(int[] nums1, int[] nums2) {
        int n = nums2.length;
        Map<Integer, Integer> map = new TreeMap<>();
        Map<Integer, Integer> set = new HashMap<>(nums1.length);
        for (int i : nums1) {
            set.merge(i, 1, Integer::sum);
        }
        for (int v2 : nums2) {
            for (int v1 : nums1) {
                map.merge(v2 - v1, 1, Integer::sum);
            }
        }
        int res = Integer.MAX_VALUE;
        here:
        for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
            Map<Integer, Integer> tmp = new HashMap<>(set);
            if (entry.getValue() >= n) {
                for (int i : nums2) {
                    if (tmp.get(i - entry.getKey()) == null || tmp.get(i - entry.getKey()) <= 0) {
                        continue here;
                    }
                    tmp.merge(i - entry.getKey(), -1, Integer::sum);
                }
                res = Math.min(res, entry.getKey());
            }
        }
        return res;
    }

}

性能