我有一个整数列表,我想对它们进行标准化,以便它们的总和是100,所以例如(1, 1, 1, 1) --> (25, 25, 25, 25)
。这相对容易实现:
int sum = calcSum(list);
double factor = 100.0 / sum;
List<Integer> newList = Lists.newArrayList();
for (Integer i : list) {
newList.add(i*factor);
}
只要总和是100的除数,这就有效。不幸的是,这会映射(1, 2) --> (33, 66)
而不是(1, 2) --> (33, 67)
。我可以为我的解决方案添加四舍五入
newList.add(i*factor); --> newList.add(Math.round(i*factor));
不幸的是,这仍然存在(1, 1, 1) --> (33, 33, 33)
的问题。我意识到在这种情况下我需要添加某种类型的决胜局,并随意选择其中一个条目为34.假设比率为(0.334, 0.333, 0.333)
我想选择第一个元素而不是任意选择。即使在完美平局的情况下,随机选择一个元素增加1也不够好,因为我可能需要增加1以上。
我可能想出一个不重复的算法,它重复选择最大值(没有选择相同的元素两次并使用任意的仲裁器)并递增它直到总和为100.是否有更好的算法来执行此操作?
答案 0 :(得分:2)
根据您想要实现的目标,您始终可以将最后一个整数设置为缺失的数量:
int currentSum = 0;
for (int i = 0; i < list.size - 2, i++) {
newList.add(list.get(i) * factor);
currentSum += list.get(i);
}
newList.add(sum - currentSum);
答案 1 :(得分:1)
您可以使用带余数的整数除法而不是浮点除法。
private static int [] divide(int ... num) {
int [] ret = new int[num.length];
int sum = sum(num);
int rem = 0;
for (int i = 0; i < ret.length; i++) {
int count = num[i]*100 + rem;
ret[i] = count / sum;
rem = count % sum;
}
return ret;
}
正如您所看到的,我们总是将剩余部分带到下一次迭代并将其添加回来。通过在下一次迭代中始终输入余数,我们总是知道何时需要添加一个&#34;跳跃数字&#34;以达到100的确切总分。
这里唯一的问题是额外的数字会被添加到最后一个元素,但我会让你弄清楚如何改变它。 :)
这种跟踪错误并将其反馈的想法是一种强大的通用策略,在许多算法中使用,尤其是在Bresenham line drawing algorithm中。