我陷入了要解决的Codility问题中,并且还为该问题收集了解决方案。
对于N个整数的给定数组A和N个整数的序列S 集{−1,1},我们定义val(A,S)如下:
val(A,S)= | sum {A [i] * S [i] for i = 0..N-1} |
(假设零个元素的总和等于零。)
对于给定的数组A,我们正在寻找这样的序列S 最小化val(A,S)。
编写函数:
class Solution {public int solution(int [] A); }
,给定一个由N个整数组成的数组A,计算出的最小值 val(A,S)的所有可能值中的val(A,S) 序列{−1,1}中N个整数的S序列。
例如,给定数组:
A [0] = 1 A [1] = 5 A [2] = 2 A [3] = -2您的函数应 返回0,因为对于S = [-1、1,-1、1],val(A,S)= 0,这是 最小可能值。
为以下假设写出有效的算法:
N是[0..20,000]范围内的整数;数组A的每个元素 是[-100..100]范围内的整数。
我有以下解决方法,
public static int solution(int[] A) {
int N = A.length;
if (N == 0) {
return 0;
}
int sum = 0;
int max = Integer.MIN_VALUE;
for (int i = 0; i < N; i++) {
int value = Math.abs(A[i]);
sum += value;
if (max < value) {
max = value;
}
A[i] = value;
}
// A = [1, 5, 2, -2]
// A(abs) = [1, 5, 2, 2]
// Max value = 5
// Sum value = 10
// counts = [0, 1, 2, 0, 0, 1]
int[] counts = new int[max + 1];
for (int value : A) {
counts[value]++;
}
// Total = [0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1]
int[] Total = new int[sum + 1];
for (int i = 1; i < Total.length; i++) {
Total[i] = -1;
}
for (int i = 1; i < counts.length; i++) {
for (int j = 0; j < Total.length; j++) {
if (Total[j] >= 0) {
Total[j] = counts[i];
} else if (j - i >= 0 && Total[j - i] > 0) {
Total[j] = Total[j - i] - 1;
}
}
}
int result = sum;
for (int i = 0; i < Total.length / 2 + 1; i++) {
if (Total[i] >= 0 && result > Math.abs(sum - 2 * i)) {
result = Math.abs(sum - 2 * i);
}
}
return result;
}
任何具有良好算法能力的人都可以向我解释解决方案吗?
答案 0 :(得分:1)
它一步一步地遍历数组的元素。由于我们要添加连续的数字,所以我们要做的就是确保总和不会变小。这就是为什么我们需要一个数字并检查总和如何变化的原因。
正式地,我们可以这样写:
max(solution([a1, a2, ..., an]) = sum(abs(a1), abs(a2), ..., abs(an)),
其中abs
表示绝对值(|x| = x * signum(x)
)。
示例:
假设我们有一个数组[1,-2,3]。绝对值数组将为[1、2、3]。我们需要从所有组合中找到最大的价值:
1 + 2 + 3
1 + 2 - 3
1 - 2 + 3
...
-1 - 2 - 3
显然,由于每个元素前的符号不会影响总和,因此我们需要考虑sum + element
或sum - element
是否更大。最大的是绝对值的总和:1 + 2 + 3
。