java—关于Codibility的minmaxdivision的解决方案的问题,它使用二进制搜索来解决

zzwlnbp8  于 2021-06-27  发布在  Java
关注(0)|答案(1)|浏览(401)

基于在线解决方案,我几乎想出了如何解决codility的minmaxdivision,但解决方案中有一个细节我正在努力确认。
问题如下:
任务描述
给定整数k,m和一个由n个整数组成的非空数组a。数组的每个元素都不大于m。
您应该将此数组划分为k个连续元素块。块的大小是0到n之间的任意整数。数组的每个元素都应该属于某个块。
从x到y的块的和等于a[x]+a[x+1]+…+是的。空块的和等于0。
大和是任何块的最大和。
例如,给定整数k=3,m=5和数组a,以便:

A[0] = 2
A[1] = 1
A[2] = 5
A[3] = 1
A[4] = 2
A[5] = 2  
A[6] = 2

例如,可以将数组划分为以下块:

[2, 1, 5, 1, 2, 2, 2], [], [] with a large sum of 15;
[2], [1, 5, 1, 2], [2, 2] with a large sum of 9;
[2, 1, 5], [], [1, 2, 2, 2] with a large sum of 8;
[2, 1], [5, 1], [2, 2, 2] with a large sum of 6.

我们的目标是尽可能地减少这一大笔钱。在上面的例子中,6是最小的大和。
编写函数:

class Solution { public int solution(int K, int M, int[] A); }

给定整数k,m和一个由n个整数组成的非空数组a,返回最小和。
例如,给定k=3,m=5和一个数组:

A[0] = 2
A[1] = 1
A[2] = 5
A[3] = 1
A[4] = 2
A[5] = 2  
A[6] = 2

函数应该返回6,如上所述。
为以下假设编写一个有效的算法:
n和k是[1..100000]范围内的整数;m是整数
在[0..10000]范围内;数组a的每个元素都是一个整数
在[0..m]范围内。
以下解决方案是100%:

public int solution(int K, int M, int[] A) {

    int min = 0;
    int max = 0;

    for (int i = 0; i < A.length; i++) {
        max += A[i];
        min = Math.max(min, A[i]);
    }

    if (K == 1)
        return max;

    if (K >= A.length)
        return min;

    int result = min;

    while (min <= max) {

        int mid = (min + max) / 2;

        if (check(mid, K, A)) {

            max = mid - 1;
            result = mid;

        } else {

            min = mid + 1;

        }

    }

    return result;
}

private boolean check(int mid, int k, int[] a) {

    int sum = 0;

    for (int i = 0; i < a.length; i++) {

        sum += a[i];

        if (sum > mid) {
            sum = a[i];
            k--;
        }

        if (k == 0)
            return false;

    }

    return true;

}

这个解决方案的思想非常简单:最小和在min(a)或sum(a)之间。我们可以使用二进制搜索来寻找最小的大和,而不是逐个迭代。对于每个候选块(mid),我们看是否有k个块不通过mid的值。
我的问题是,在上面的check()方法中,如何基于中间值找到块的数量。有些情况下,块的数量符合标准,但没有一个块的总和等于中间值。一个很好的例子是当我们有一个包含所有数组值的块,而其他块是空的。
一个很好的例子是a=[2,3,3,5,4,2,3],k=3:中间值最终得到的值是10,我们可以有3个块[2,3,3],[5,4],[2,3],但它们都不等于10。
求解算法能否输出一个中间值,即最小的大和,但该和实际上不存在?check()方法如何始终找到最小的大和,并且该最小的大和存在于数组中,而不将和值与中值进行比较?

qco9c6ql

qco9c6ql1#

有些情况下,块的数量符合标准,但没有一个块的总和等于中间值
这没关系,因为 check 会回来的 true 再低一点 mid 将被检查:一些更低 mid 最终将是一个等于某个块的和。
一个很好的例子是a=[2,3,3,5,4,2,3],k=3:中间值最终得到的值是10,我们可以有3个块[2,3,3],[5,4],[2,3],但它们都不等于10。
之后 mid = 10 以及 check 返回 true ,这将执行:

max = mid - 1;
result = mid;

通过设置 max9 , 9 最终也会被检查,并被退回。
求解算法能否输出一个中间值,即最小的大和,但该和实际上不存在?
不,因为如果这个总和不存在 check 退货 true ,那么我们就有了一个可能的较小的和-所以电流 mid 不是最低要求。如果算法得到100%,那么它将输出这个较小的值。
也可以根据问题陈述中给出的定义来考虑:
大和是任何块的最大和。
[...]
我们的目标是尽可能地减少这一大笔钱。在上面的例子中,6是最小的大和。
所以,根据定义,最小和就是某个块的和。
check()方法如何始终找到最小的大和,并且该最小的大和存在于数组中,而不将和值与中值进行比较?
这个 check 方法本身找不到最小和。它只告诉你一个给定的和 mid 参数)是有效的(即,如果我们可以将数组拆分为 K 最大和<= mid ).
是二进制搜索找到最小的大和。

相关问题