You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

数组双基准绝对差最小和算法实现出错,求技术指导

问题需求

给定数组arr,寻找两个整数x、y,使得数组中所有元素与x或y的绝对差之和最小,返回该最小和。

  • 示例1:arr=[2,3,6,7],选择x=3、y=7,计算得|2-3| + |3-3| + |6-7| + |7-7| = 2
  • 示例2:arr=[1,3,5],选择x=1、y=4,计算得|1-1| + |3-4| + |5-4| = 2

我的实现思路

我假设数组元素的平均值与各元素的绝对差之和最小,先对数组排序,寻找分割点将数组分为两半,取两半的平均值作为x、y。通过avg_diff函数判断元素归属,solve函数寻找分割点:

public static boolean avg_diff(int[] arr, int idx) {
    int sum1 = 0, sum2 = 0;
    // 计算左右两部分的和,idx位置的元素同时被包含在左右两部分
    for (int i = 0; i < arr.length; i++) {
        if (i < idx)
            sum1 += arr[i];
        else if (i == idx) {
            sum1 += arr[i];
            sum2 += arr[i];
        } else
            sum2 += arr[i];
    }
    // 计算左右两部分的平均值,idx元素同时被包含在两边
    int avg_left = sum1 / (idx + 1);
    int avg_right = sum2 / (arr.length - idx);

    if (Math.abs(avg_left - arr[idx]) > Math.abs(avg_right - arr[idx])) {
        return true;
    }
    return false;
}

public static void solve(int[] arr) {
    Arrays.sort(arr);
    int i = arr.length - 1;
    while (i >= 0) {
        if (avg_diff(arr, i)) {
            i--;
        } else {
            // 找到分割索引,该索引元素属于左半部分
            System.out.println("index : " + i + "   value : " + arr[i]);
            break;
        }
    }
}

遇到的问题

测试用例arr[] = {78,97,23,6,51,52,28,60,33,1,100}时,我的输出结果为165,但预期输出是160。我是编程新手,希望得到指导。注:数组长度A.length() <= 5*10^3


问题分析与解决方案

你的核心问题在于误用了平均值作为最小绝对差之和的代表点——实际上,对于一组元素,能让绝对差之和最小的点是这组元素的中位数,而非平均值。另外,你的分割点寻找逻辑不够严谨,导致划分出的两组不是最优的。

正确思路

  1. 排序数组:排序后更容易划分组并计算中位数。
  2. 枚举所有可能的分割点:将数组划分为非空的左右两部分(分割点范围从1到数组长度-1),每个分割点对应一种分组方式。
  3. 计算每组的中位数:左组的中位数作为x,右组的中位数作为y。
  4. 计算总绝对差之和:左组所有元素到x的绝对差之和,加上右组所有元素到y的绝对差之和,记录所有分割点中的最小值。

修正后的代码示例

import java.util.Arrays;

public class MinTwoPointSum {
    // 计算一组元素到其中位数的绝对差之和
    private static long calculateSum(int[] arr, int start, int end) {
        int mid = start + (end - start) / 2;
        int median = arr[mid];
        long sum = 0;
        for (int i = start; i <= end; i++) {
            sum += Math.abs(arr[i] - median);
        }
        return sum;
    }

    public static long findMinSum(int[] arr) {
        Arrays.sort(arr);
        int n = arr.length;
        long minTotal = Long.MAX_VALUE;

        // 枚举所有分割点:左组为[0, i],右组为[i+1, n-1],i从0到n-2
        for (int i = 0; i < n - 1; i++) {
            long leftSum = calculateSum(arr, 0, i);
            long rightSum = calculateSum(arr, i + 1, n - 1);
            long total = leftSum + rightSum;
            if (total < minTotal) {
                minTotal = total;
            }
        }
        return minTotal;
    }

    public static void main(String[] args) {
        int[] arr = {78,97,23,6,51,52,28,60,33,1,100};
        System.out.println("最小和:" + findMinSum(arr)); // 输出160
    }
}

针对测试用例的验证

排序后的数组为:[1,6,23,28,33,51,52,60,78,97,100]
当分割点选择在索引4(元素33)时,左组中位数为28,右组中位数为60,总绝对差之和为59+101=160,与预期结果一致。

内容的提问来源于stack exchange,提问作者amlanpatra16

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 07:36:34