从数组中找到元素的最小绝对和
Posted
技术标签:
【中文标题】从数组中找到元素的最小绝对和【英文标题】:find the lowest absolute sum of elements from an array 【发布时间】:2018-07-15 07:05:59 【问题描述】:我试图从下面提供的 Codility 中的问题中理解解决方案,
对于给定的包含 N 个整数的数组 A 和来自集合 −1, 1 的包含 N 个整数的序列 S,我们将 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,从集合 −1, 1。
例如,给定数组:
A[0] = 1
A[1] = 5
A[2] = 2
A[3] = -2
你的函数应该返回 0,因为对于 S = [−1, 1, −1, 1],val(A, S) = 0,这是可能的最小值。
假设:
N is an integer within the range [0..20,000];
each element of array A is an integer within the range [−100..100].
Complexity:
预期的最坏情况时间复杂度为 O(N*max(abs(A))2); 预期的最坏情况空间复杂度为 O(N+sum(abs(A)))(不计算输入参数所需的存储空间)。
在过去的几个小时里,我找到了想要了解的解决方案。
public static int solution(int[] A)
int N = A.length;
int sum = 0;
int max = 0;
for (int i = 0; i < N; i++)
A[i] = Math.abs(A[i]);
sum += A[i];
max = Math.max(A[i], max);
int[] counts = new int[max + 1];
for (int i = 0; i < N; i++)
counts[A[i]] += 1;
int[] Total = new int[sum + 1];
Arrays.fill(Total, -1);
Total[0] = 0;
// Segment I
for (int i = 1; i <= max; i++)
if (counts[i] > 0)
for (int j = 0; j <= sum; j++)
// j th index is zero or positive
if (Total[j] >= 0)
Total[j] = counts[i];
// (i-j) th index is positive
else if ((j - i) >= 0 && Total[j - i] > 0)
Total[j] = Total[j - i] - 1;
int result = sum;
// Segment II
for (int i = 0; i < sum / 2 + 1; i++)
// i- th index if zero or positive
// BODMAS_RULE = Brackets, Orders, Division, Multiplication, Addition, Subtraction
if (Total[i] >= 0)
result = Math.min(result, sum - 2 * i);
return result;
如果有人能解释循环的最后两段发生了什么,那将非常有帮助。我只是在几行文字中寻找一个简短的解释。
更新
我想了解为什么我们在第一段的 for 循环中使用条件。此外,为什么我们要迭代到第二个 for 循环中的sum / 2 + 1
。谢谢你。
【问题讨论】:
【参考方案1】:要对所需属性求和,您可以找到数组 A 的子集,其总和尽可能接近总和的一半。
它有点像well-knownsubset sum problem
,可以通过动态编程方法使用维度对应于总和的附加数组来解决(注意数组Total
)。
请注意,该问题的解决方案仅处理正数,因此您必须对其进行修改以使用负数(例如您的示例 A[3] = -2
)。
此代码使数组total
的长度为sum+1
,并保存数组counts
中每个值的计数。
在第一阶段,代码用所有可能总和的非否定条目填充总表。考虑简单的设定值:count (2:3; 3:2)
.
第一轮用值 3,2,1,0 填充条目 0,2,4,6。
第二轮更改所有非负数的三分球和
从非负条目(例如,4--> 4+3 ->4+6
)为链构建递减序列。之后,我们有总数组[2,-1,2,1,2,1,2,1,0,1,0,-1,0]
,在 1,11 处有负条目(不可能的总和)。请注意,这种方法不存储信息 - 使用了哪些项目来计算所有可能的总和,因此您必须进行更多修改。
【讨论】:
好的,我试图理解提供的注释,但它仍然没有多大意义。您介意详细说明答案吗? 但是显示的代码已经使用了动态编程——它填充了总数组(第 1 段),然后找到最接近(接近一半)的填充条目(第 2 段) 你明白子集和问题等价于你的任务吗? 是的,但它仍然对我没有帮助。你为我指明了正确的方向已经很好了。如果您能花时间写一个详尽的答案,我将不胜感激。谢谢。 至少我们为什么要使用这些条件?if (Total[j] >= 0) Total[j] = counts[i]; /* * (i-j) th index is positive * */ else if ((j - i) >= 0 && Total[j - i] > 0) Total[j] = Total[j - i] - 1;
在第一段。以上是关于从数组中找到元素的最小绝对和的主要内容,如果未能解决你的问题,请参考以下文章