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