【问题标题】:Java: divide number into equals parts or approximate to each otherJava:将数字分成相等的部分或彼此近似
【发布时间】:2015-12-09 03:45:24
【问题描述】:

我有一个数字 = 20。我想将这个数字分成 N 等份或彼此近似。 N 可能从 1 到 20。

我写了这段代码:

ArrayList<Integer> c = new ArrayList<>();
int num = 20;
int count = N; //where N some number (from 1 to 20)
int val = (int) Math.floor(num / count);

for (int i = 0; i < count; i++) {
    c.add(val);
}
c.set(0, c.get(0) + num - sum(c));

它工作正常,例如,当 count = N = 3 时。我得到:8、6、6 (8+6+6=20)。但是如果 count = N = 12 我得到下一个结果:9、1、1、1、1、1、1、1、1、1、1、1(总和 = 20)。我希望结果将是下一个:1、2、2、2、2、2、2、2、2、1、1、1(总和 = 20)。这可能吗?

【问题讨论】:

    标签: java android numbers integer


    【解决方案1】:

    您计算下一个部分的大小,然后减小值并重复:

    private static int[] splitIntoParts(int whole, int parts) {
        int[] arr = new int[parts];
        int remain = whole;
        int partsLeft = parts;
        for (int i = 0; partsLeft > 0; i++) {
            int size = (remain + partsLeft - 1) / partsLeft; // rounded up, aka ceiling
            arr[i] = size;
            remain -= size;
            partsLeft--;
        }
        return arr;
    }
    

    如果你愿意,方法可以被挤压,虽然保持上面那样更好,因为它把参数当作不可变的,并且理清了逻辑:

    private static int[] splitIntoParts(int whole, int parts) {
        int[] arr = new int[parts];
        for (int i = 0; i < arr.length; i++)
            whole -= arr[i] = (whole + parts - i - 1) / (parts - i);
        return arr;
    }
    

    测试

    for (int parts = 0; parts <= 25; parts++)
        System.out.println(parts + ": " + Arrays.toString(splitIntoParts(20, parts)));
    

    输出

    0: []
    1: [20]
    2: [10, 10]
    3: [7, 7, 6]
    4: [5, 5, 5, 5]
    5: [4, 4, 4, 4, 4]
    6: [4, 4, 3, 3, 3, 3]
    7: [3, 3, 3, 3, 3, 3, 2]
    8: [3, 3, 3, 3, 2, 2, 2, 2]
    9: [3, 3, 2, 2, 2, 2, 2, 2, 2]
    10: [2, 2, 2, 2, 2, 2, 2, 2, 2, 2]
    11: [2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1]
    12: [2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1]
    13: [2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1]
    14: [2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1]
    15: [2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    16: [2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    17: [2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    18: [2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    19: [2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    20: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
    21: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0]
    22: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0]
    23: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0]
    24: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
    25: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
    

    注意0 返回空数组。如果失败,请添加 if 语句。负值将因NegativeArraySizeException 而失败。如您所见,太多的部分将简单地返回0 大小的部分。同样,如果失败,请添加 if 语句

    【讨论】:

      【解决方案2】:

      给你

      int x = 20;
      int n = 12;
      ArrayList<Integer> list = new ArrayList<>();
      int f = x / n;
      int r = x % n;
      for(i = 0; i < n; i++) {
          if(i <= n - r) list.add(f);
          else list.add(f + 1)
      }
      

      【讨论】:

      • 谢谢!但我们必须有一些正确的代码,因为当 n=2 时,结果 = 10,而不是 10,10。
      • @BinoyBabu 我认为你应该在你的代码 list.add(f+1) 和 list.add(f) 中切换,因为如果 x = 8 和 n=3 它会产生错误的结果(它将是:[2,2,3] 而不是预期的:[3,3,2])
      【解决方案3】:

      我稍微修改了您的代码。看看这是否有效。

      ArrayList<Integer> c = new ArrayList<>();
      int num = 20;
      int count = 12; //where N some number (from 1 to 20)
      int val = (int) Math.floor(num / count);
      int sum = 0;
      int max = val;
      for (int i = 0; i < count; i++) {
          c.add(val);
          sum+=c.get(i);
      }
      
      int temp = c.get(0) + num - sum;
      int i=1;
      while (temp > max) {
          if (i>=c.size())
              i = 1;
          temp-=1;
          c.set(i, c.get(i) + 1);
          if (max < c.get(i))
              max = c.get(i);
          i++;
      }
      c.set(0, temp);
      System.out.println(c);
      

      【讨论】:

      • 非常复杂和低效的代码。示例:在第一个循环中,c.get(i) 将始终检索刚刚添加的值,因此它等于val,除了您获得数组查找的成本和对Integer 的拆箱。将其更改为sum+=val 将突出显示val 永远不会更改的事实,因此如果您只是将sum 初始化为int sum = val * count,则不需要该代码。
      【解决方案4】:

      我有一个简单的解决方案(虽然不是最好的) -

      int[] parts = new int[count];
      
      int j = 0;
      for (int i=1; i<=num; i++) {
          parts[j] += 1;
          j++;
          if (j == count) {
              j = 0;
          }
      }
      

      【讨论】:

      • 您不必将数组初始化为0,JVM 已经完成了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-23
      • 2011-05-27
      • 2012-10-16
      • 2014-03-18
      • 2018-05-24
      • 1970-01-01
      • 2016-03-20
      相关资源
      最近更新 更多