【问题标题】:Is there a way to allow for the number of for loops and array elements to be variable in algorithm? - java有没有办法让 for 循环和数组元素的数量在算法中可变? - 爪哇
【发布时间】:2022-01-01 16:31:00
【问题描述】:

目前正在编写一个程序,用于查找数组中 3 个给定数字的最佳比例。然而,我目前的代码只需要 3 个数字并安排它们以找到最接近 100 的 3 个数字排列。我需要代码具有适应性,以便它采用 3 个数字并给出最接近 100 的 n 数字排列。

public static int[] mmru(int[] array) {
    int result = 1000;
    int[] ideal = new int[0];
    int closestResult = 100;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            for (int k = 0; k < 3; k++) {
                result = 100 - array[i] - array[j] - array[k];
                if (result == 0) {
                    ideal = new int[]{array[i], array[j], array[k]};
                    return ideal;
                } else {
                    if (result < closestResult && result > 0) {
                        ideal = new int[]{array[i], array[j], array[k]};
                        closestResult = result;
                    }
                }

            }
        }
    }
    return ideal;
}

我现在的解决方案是手动添加更多 for 循环和数组元素。

示例 - 一个由 3 个数字组成的数组,使用 3 个数字输出 8 个数字的排列以最接近 100。例如。 [8,13,15] 给出 [8,8,13,13,13,15,15,15] 的输出

public static int[] mmrh8(int[] array) {
    int result = 1000;
    int[] ideal = new int[0];
    int closestResult = 100;
    for (int i = 0; i < 3; i++) {
        for (int j = 0; j < 3; j++) {
            for (int k = 0; k < 3; k++) {
                for (int l = 0; l < 3; l++) {
                    for (int m = 0; m < 3; m++) {
                        for (int n = 0; n < 3; n++) {
                            for (int o = 0; o < 3; o++) {
                                for (int p = 0; p < 3; p++) {
                                    result = 100 - array[i] - array[j] - array[k] - array[l] - array[m] - array[n] - array[o] - array[p];
                                    if (result == 0) {
                                        ideal = new int[]{array[i], array[j], array[k], array[l], array[m], array[n], array[o], array[p]};
                                        return ideal;
                                    } else {
                                        if (result < closestResult && result > 0) {
                                            ideal = new int[]{array[i], array[j], array[k], array[l], array[m], array[n], array[o], array[p]};
                                            closestResult = result;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return ideal;
}

有没有办法让for循环和数组元素的数量可变?

任何帮助表示感谢!

【问题讨论】:

  • 我希望这是一个XY Problem 类型的问题。

标签: java loops for-loop recursion iteration


【解决方案1】:

正如 cmets 中所指出的,对于这个问题可能有更有效的解决方案,但如果您想保持尝试所有可能组合的蛮力方法,那么可以这样做:

您的for-loops 所做的是有效地给出所有 8 位数字与仅数字 0、1 和 2 的所有可能组合,然后将其用作给定数字数组中的索引。所以你需要计算这些。这可以通过枚举它们来完成:

0: 00000000
1: 00000001
2: 00000002
3: 00000010
4: 00000011
5: 00000012
6: 00000020
...
6561 (3^8): 22222222

这相当于将计数器解释为ternary system 中的数字(或任何不同的数字系统,具体取决于给定数字的数量)。然后可以使用this 答案计算该数字的位数,将 10 换成三进制系统的 3。

这导致以下代码获取所有可能的索引组合:

// the length of the input array
int base = 3;
// must have same length as desired result length
int[] indexArray = new int[8];

// there are base to the power of length possible combinations
for (int counter = 0; counter < Math.pow(base, indexArray.length); counter++) {
  // retrieve digits as in linked answer
  int counterCopy = counter;
  for (int i = 0; i < indexArray.length; i++) {
    indexArray[i] = counterCopy % base;
    counterCopy /= base;
  }
  
  // insert your code, indexArray[0] is your "i", indexArray[1] is your "j" and so on
  System.out.println(Arrays.toString(indexArray));
}

【讨论】:

    【解决方案2】:

    从您的示例看来,您的解决方案应该代表三个乘法因子,以应用于数组中给定的三个值。您希望这三个因素与给定数组值的乘积之和最接近 100。

    因此,如果给定三个值 v[0]、v[1] 和 v[2],您希望求解 a、b 和 c,使得以下公式的结果最接近 100 :

    a * v[0] + b * v[1] + c * v[2]
    

    与其构建整个数组,不如解决这三个值。

    int maxUnder100=0;
    int minOver100=99999;
    for (int a=0; a<=100/v[0]+1; a++) {
        for (int b=0; b<=100/v[1]+1; b++) {
            for (int c=0; c<=100/v[2]+1; c++) {
                int calc=a*v[0]+b*v[1]+c*v[2];
                if (calc>=100 && calc<maxUnder100) {
                    maxUnder100=calc;
                    // store your best max solution somehow
                }
                if (calc<=100 && calc>minOver100) {
                    minOver100=calc;
                    // store your best min solution somehow
                }
            }
        }
    }
    

    一旦你有了这些乘法因子,代表你的最终值数组应该是微不足道的。

    注意:我对每个 for 循环的最大值有点看中,但肯定还有改进的余地。

    【讨论】:

      【解决方案3】:

      这是一种方法。

      这个想法是生成一系列索引,这些索引将引用构成总和的候选者。例如:

      • 给出最终数组中的元素个数为8 - 称为maxElements
      • 填充数组的候选列表是{8,13,15}

      然后从0,0,0 to 7,7,7 生成一个索引数组。所以[1,3,4] 会说使用一个8、三个13's 和四个15's。请注意,计数总和等于maxElements 很重要。所以1 + 3 + 4 = 8。在返回当前索引计数的update 方法中负责创建索引数组和维护计数。如果该计数与 maxElement 值不匹配,则不会用于填充 resultArray

      根据当前计算的数组是否更接近targetSum来更新和保存结果数组。

      record 用于容纳和返回最终值。也可以使用普通的class

      record Results(int sum, int[] array) {
          @Override
          public String toString() {
              return String.format("sum = %d : %s", sum,
                      Arrays.toString(array));
          }
      }
      

      运行示例。

      int[] candidates = { 8, 13, 15};
      for (int maxElements = 1; maxElements < 10; maxElements++) {
          Results result = bestSum(100, maxElements, candidates);
          System.out.println(result);
      }
      

      打印

      sum = 15 : [15]
      sum = 30 : [15, 15]
      sum = 45 : [15, 15, 15]
      sum = 60 : [15, 15, 15, 15]
      sum = 75 : [15, 15, 15, 15, 15]
      sum = 90 : [15, 15, 15, 15, 15, 15]
      sum = 101 : [13, 13, 15, 15, 15, 15, 15]
      sum = 100 : [8, 8, 13, 13, 13, 15, 15, 15]
      sum = 100 : [8, 8, 8, 8, 8, 15, 15, 15, 15]
      

      构建indices数组并维护并返回的更新方法 指数之和。

      public static int update(int[] indices, int prevSum,
              int maxElements) {
          maxElements++;
          for (int i = indices.length - 1; i >= 0; i--) {
              indices[i]++;
              prevSum++;
              if (indices[i] < maxElements) {
                  return prevSum;
              }
              prevSum -= indices[i];
              indices[i] = 0;
          }
          return prevSum;
      }
      

      计算最佳和的主要方法

      public static Results bestSum(int targetSum, int maxElements,
              int[] candidates) {
          
          int delta = Integer.MAX_VALUE;
          int[] saveResultArray = new int[maxElements];
          int[] indicesArray = new int[candidates.length];
          int i = maxElements;
          int totalIndices = 0;
          for (int v = 1;
                  v < Math.pow(maxElements+1,candidates.length); v++) {
      
              totalIndices = update(indicesArray, totalIndices, maxElements);
          
              // is the indices array usable, if not, ignore.
              if (totalIndices != maxElements) {
                  continue;
              }
              
              int[] resultArray = new int[maxElements];
              int nn = 0;
              int tempSum = 0;
              // iterate over the indices Array.  For each value
              // add that many of the candidates array to the result array.
              
              for (int k = 0; k < indicesArray.length; k++) {
                  for (int j = 0; j < indicesArray[k]; j++) {
                      resultArray[nn++] = candidates[k];
                      tempSum += candidates[k];
                  }
              }
              // based on differences of previous computations,
              // update the differences and save the result array accordingly.
              
              if (tempSum == targetSum) {
                  delta = 0;
                  saveResultArray = resultArray;
                  break;
              }
              int diff = tempSum - targetSum;
              if (Math.abs(diff) < Math.abs(delta)) {
                  saveResultArray = resultArray;
                  delta = diff;
              }
          }
          return new Results(targetSum + delta, saveResultArray);
      }
      

      这是一种蛮力算法,其中许多值仅被计算为被忽略。随着候选列表的增长,算法会大大减慢,因为这会增加循环迭代次数。

      【讨论】:

        猜你喜欢
        • 2023-03-04
        • 1970-01-01
        • 2021-03-29
        • 1970-01-01
        • 2011-09-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多