规范化整数

时间:2015-06-29 17:10:07

标签: algorithm java-7

我有一个整数列表,我想对它们进行标准化,以便它们的总和是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.是否有更好的算法来执行此操作?

2 个答案:

答案 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中。