数列差异的最小化 | 豆包MarsCode AI刷题

179 阅读4分钟

问题描述

小R在研究两个数列之间的关系。他给定了两个数列 a 和 b,长度分别为 n 和 m,并设计了一个有趣的公式:∣(a[i]−b[j])2−k2∣∣(a[i]−b[j])2−k2∣,其中 k 是给定的一个整数, 0≤i<n0≤i<n,0≤j<m0≤j<m。现在,小R想知道如何选择数列 a 和 b 中的元素 a[i]a[i] 和 b[j]b[j],使得这个公式的值达到最小。

给定两个整数数列 a(长度为 n) 和 b(长度为 m),以及一个整数 k,你需要找到这个公式的最小值。

约束条件

  • 1≤n,m≤1051≤n,m≤105
  • 0≤k≤1090≤k≤109
  • 0≤a[i],b[j]≤1090≤a[i],b[j]≤109

代码思路分析

  1. 计算差值平方数组c: - 首先定义了一个数组c,用于存储(a[i] - b[i])^2的各种可能结果。通过两层循环遍历列表ab中的元素,计算每个组合的差值平方,并将结果存入数组c中。
  2. 去重与排序数组c: - 使用Java 8的流操作,先对数组c进行去重操作,去除重复的元素,然后对去重后的数组进行排序,以便后续进行二分查找。
  3. 二分查找及结果计算: - 设定二分查找的左右边界leftright,以及中间索引middle。在循环中,根据中间元素c[middle]与目标值k * k的大小关系来调整查找范围。 - 如果c[middle]等于k * k,说明找到了完全匹配的差值平方,直接返回0。 - 如果c[middle]大于k * k,则将查找范围缩小到左半部分,更新rightmiddle。当left大于right时,表示未找到完全匹配的值,此时需要根据边界情况返回与k * k差值绝对值最小的相邻元素的差值绝对值。 - 如果c[middle]小于k * k,则将查找范围缩小到右半部分,更新leftmiddle。同样,当left大于right时,根据边界情况返回与k * k差值绝对值最小的相邻元素的差值绝对值。
  4. 主函数中的测试用例: - 在main方法中,定义了多个测试用例,分别创建了不同的列表ab,并调用solution函数进行测试,然后通过比较返回结果与预期结果是否相等来验证函数的正确性。 ### 代码总结 这段代码的主要目的是实现一个功能,给定两个整数列表ab以及整数nm(分别表示列表ab的大小)和k,通过计算(a[i] - b[i])^2的所有可能值,去重并排序后,利用二分查找在这些值中寻找与k * k最接近的值(如果找不到完全相等的值),并返回相应的差值绝对值最小值。在main方法中通过几个简单的测试用例对solution函数进行了初步的功能验证。整体代码逻辑清晰,通过合理运用数组操作、流操作以及二分查找算法来实现目标功能,但可能还需要更多全面的测试用例来确保在各种情况下的正确性和稳定性。 代码实现:
import java.util.Arrays;
import java.util.List;

public class Main {
    public static int solution(int n, int m, int k, List<Integer> a, List<Integer> b) {
        // Please write your code here
        //定义一个数组存储(a[i]-b[i])^2的各种情况然后排序
        int[] c = new int[n * m];
        int index = 0;
        for (int i = 0; i < a.size(); i++) {
            for (int j = 0; j < b.size(); j++) {
                c[index] = (a.get(i) - b.get(j)) * (a.get(i) - b.get(j));
                index++;
            }
        }
        c=Arrays.stream(c).distinct().toArray();
        Arrays.sort(c);

        //二分查找K^2如果找到则直接返回0否则找其相邻的数组元素进行公式运算后比较大小取最小的数
        int left = 0;
        int right = c.length - 1;
        int middle = (left + right) / 2;
        while (true) {
            if (c[middle] == k * k) {
                return 0;
            } else if (c[middle] > k * k) {
                right = middle - 1;
                middle = (left + right) / 2;
                if (left > right) {
                    if (right == -1) return Math.abs(c[0] - k * k);
                    return Math.min(Math.abs(c[right] - k * k), Math.abs(c[right + 1] - k * k));
                }
            } else {
                left = middle + 1;
                middle = (left + right) / 2;
                if (left > right) {
                    if (left == c.length) return Math.abs(c[c.length-1] - k * k);
                    return Math.min(Math.abs(c[left] - k * k), Math.abs(c[left - 1] - k * k));
                }
            }

        }
    }

    public static void main(String[] args) {
        // You can add more test cases here
        // case 1
        List<Integer> a1 = Arrays.asList(5, 3, 4, 1, 2);
        List<Integer> b1 = Arrays.asList(0, 6, 7, 9, 8);
        System.out.println(solution(5, 5, 1, a1, b1) == 0);

        // case 2
        List<Integer> a2 = Arrays.asList(5, 3, 4, 1, 2);
        List<Integer> b2 = Arrays.asList(0, 6, 7, 9, 8);
        System.out.println(solution(5, 5, 0, a2, b2) == 1);

        // case 3
        List<Integer> a3 = Arrays.asList(5, 3, 4, 1, 2);
        List<Integer> b3 = Arrays.asList(0, 6, 7, 9, 8, 11);
        System.out.println(solution(5, 6, 3, a3, b3) == 0);
    }
}