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

如何分割double数组使两部分和差绝对值最小,优化现有C#实现

数组最小和差拆分问题优化

问题描述

给定元素可重复的double类型数组,需拆分为arrA和arrB两个数组,要求两数组和的差值的绝对值最小,返回拆分后的两个数组以及对应的最小绝对差值。原有实现无法覆盖所有场景,存在测试用例不通过的问题。

原有错误实现代码

static double Divide_A_B(List<double> args, out List<double> a, out List<double> b)
{
    var array = args;
    int middleIndex = array.Count / 2;
    if (array.Count == 1)
    {
        a = array;
        b = new List<double>();
        return Math.Abs(array[0]);
    }
    else if (array.Count == 2)
    {
        a = new List<double>() { array[0] };
        b = new List<double>() { array[1] };
        return Math.Abs(array[0] - array[1]);
    }
    var (leftArray, rightArray) = (new List<double>(), new List<double>());
    for (int i = 0; i < array.Count; i++)
    {
        if (i <= middleIndex)
        {
            leftArray.Add(array[i]);
        }
        else
        {
            rightArray.Add(array[i]);
        }
    }
    double diff = 0;
    while (true)
    {
        (double leftSum, double rightSum) = (leftArray.Sum(), rightArray.Sum());

        if (leftSum < rightSum)
        {
            var tempArray = leftArray;
            leftArray = rightArray;
            rightArray = tempArray;
            var tempSum = leftSum;
            leftSum = rightSum;
            rightSum = tempSum;
        }
        diff = leftSum - rightSum;
        int flag = 0;
        for (int i = 0; i < leftArray.Count; i++)
        {
            if (leftArray[i] > 0)
            {
                if (leftArray[i] <= diff / 2 || leftArray[i] < diff)
                {
                    rightArray.Add(leftArray[i]);
                    double num = leftArray[i];
                    leftArray.Remove(leftArray[i]);
                    flag++;
                    leftSum -= num;
                    rightSum += num;
                    break;
                }
            }

            for (int j = 0; j < rightArray.Count; j++)
            {
                double diffAfterSwap = Math.Abs((leftSum - leftArray[i] + rightArray[j]) - (rightSum - rightArray[j] + leftArray[i]));
                if (diffAfterSwap < diff)
                {
                    var (targetLeftNum, targetRightNum) = (leftArray[i], rightArray[j]);
                    leftArray.Remove(targetLeftNum);
                    leftArray.Add(targetRightNum);
                    rightArray.Remove(targetRightNum);
                    rightArray.Add(targetLeftNum);
                    flag++;
                    diff = diffAfterSwap;
                    break;
                }
            }

        }

        for (int i = 0; i < rightArray.Count; i++)
        {
            if (rightArray[i] < 0)
            {
                if (Math.Abs(rightArray[i]) <= diff / 2 || Math.Abs(rightArray[i]) < diff)
                {
                    leftArray.Add(rightArray[i]);
                    double num = rightArray[i];
                    rightArray.Remove(rightArray[i]);
                    rightSum -= num;
                    leftSum += num;
                    flag++;
                    break;
                }
            }
            for (int j = 0; j < leftArray.Count; j++)
            {
                double diffAfterSwap = Math.Abs(rightSum - leftSum - 2 * rightArray[i] + 2 * leftArray[j]);
                if (diffAfterSwap < diff)
                {
                    var (targetLeftNum, targetRightNum) = (leftArray[j], rightArray[i]);
                    rightArray.Remove(targetRightNum);
                    rightArray.Add(targetLeftNum);
                    leftArray.Remove(targetLeftNum);
                    leftArray.Add(targetRightNum);
                    flag++;
                    diff = diffAfterSwap;
                    break;
                }
            }
        }
        if (flag == 0)
        {
            break;
        }
    }
    a = leftArray;
    b = rightArray;
    return diff;
}

失败测试用例

测试用例数组总和为2892,理想拆分后两数组和均为1446,差值应为0,但原有算法返回差值194。

static void Main(string[] args)
{
    List<double> li = new List<double>() { 310, 226, 231, 218, 291, 267, 321, 332, 352, 344 };
    List<double> a,b = new List<double>();
    double diff = Divide_A_B(li, out a, out b);
    Console.WriteLine("A:");
    foreach (var item in a)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine("B:");
    foreach (var item in b)
    {
        Console.WriteLine(item);
    }
    Console.WriteLine($"diff: { diff}");
    Console.ReadKey();
}

原有代码问题分析

  • 初始拆分逻辑不合理:直接按索引位置拆分前半段到左数组,完全不考虑元素大小,很容易陷入局部最优,无法得到全局最优解
  • 调整逻辑提前跳出:只要找到第一个可移动/交换的元素就直接break,不会选择最优的调整对象,大量能缩小差值的调整被跳过
  • 移动判断逻辑冗余有漏洞:leftArray[i] <= diff / 2 || leftArray[i] < diff条件重复,且没有优先选择最接近diff/2的元素移动,调整效率极低
  • 缺失排序前置处理:数组排序后可以大幅提升调整效率,也能避免很多无意义的判断

优化后实现方案

优化采用「降序排序+贪心初始分配+迭代交换优化」的思路,先排序数组,初始分配时每次把当前元素放到和更小的数组中,之后再遍历所有可能的元素交换进一步缩小差值,直到没有可优化的空间。

static double Divide_A_B(List<double> args, out List<double> a, out List<double> b)
{
    // 前置排序:降序排列
    var sortedArray = args.OrderByDescending(x => x).ToList();
    var leftArray = new List<double>();
    var rightArray = new List<double>();
    double leftSum = 0, rightSum = 0;
    
    // 贪心初始分配
    foreach (var num in sortedArray)
    {
        if (leftSum <= rightSum)
        {
            leftArray.Add(num);
            leftSum += num;
        }
        else
        {
            rightArray.Add(num);
            rightSum += num;
        }
    }

    double diff = Math.Abs(leftSum - rightSum);
    bool hasImprove;
    // 迭代交换优化
    do
    {
        hasImprove = false;
        // 遍历所有可能的交换组合,找最优交换
        for (int i = 0; i < leftArray.Count; i++)
        {
            for (int j = 0; j < rightArray.Count; j++)
            {
                double newDiff = Math.Abs((leftSum - leftArray[i] + rightArray[j]) - (rightSum - rightArray[j] + leftArray[i]));
                if (newDiff < diff)
                {
                    // 执行交换
                    var temp = leftArray[i];
                    leftArray[i] = rightArray[j];
                    rightArray[j] = temp;
                    // 更新和与差值
                    leftSum = leftSum - temp + rightArray[j];
                    rightSum = rightSum - rightArray[j] + temp;
                    diff = newDiff;
                    hasImprove = true;
                    // 找到更优交换后重启遍历,避免遗漏其他优化
                    i = leftArray.Count;
                    j = rightArray.Count;
                }
            }
        }
    } while (hasImprove);

    a = leftArray;
    b = rightArray;
    return diff;
}

优化后代码运行测试用例可得到差值为0的正确结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:45:00