如何使用递归来简化重复代码?

时间:2019-06-25 23:12:28

标签: java recursion

我有三角形/树吗?任何大小的M。

在这种情况下,大小M为3:

  1
 2 3
4 5 6     

我的目标是输出所有组合,就像您从上到下遍历一样。结果将是{124} {125} {135} {136}

我如何将for循环与递归结合起来以简化操作

private ArrayList<int[]> listOfCombinations = new ArrayList<int[]>();
public void callSequence(int[] combo, int size, int n) {

    for (int i = 0; i < 4 && size >= 3; i++) {
        // System.out.println("combinations array :" + combo[0] + combo[1] + combo[2]);
        listOfCombinations.add(combo);
        listOfCombinations.get(i)[0] = 1;
        System.out.print(listOfCombinations.get(i)[0]);
    }
    System.out.println();
    for (int i=0; i < 2; i++) {
        listOfCombinations.add(combo);
        listOfCombinations.get(i)[1] = 2;
        System.out.print(listOfCombinations.get(i)[1]);
    }
    for (int i=2; i < 4; i++) {
        listOfCombinations.add(combo);
        listOfCombinations.get(i)[1] = 3;
        System.out.print(listOfCombinations.get(i)[1]);
    }
    System.out.println();
    for (int i=4; i<=5; i++) {
        listOfCombinations.get(i)[2] = i;
        System.out.print(listOfCombinations.get(i)[2]);
    }
    for (int i=5; i<=6; i++) {
        listOfCombinations.get(i)[2] = i;
        System.out.print(listOfCombinations.get(i)[2]);
    }

当我调用此函数时,它将打印

 1 1 1 1
 2 2 3 3 
 4 5 5 6

所以数组是{1,2,4} {1,2,5} {1,3,5} {1,3,6},这是正确的输出,但这是一个不好的方法。我试图考虑如何用递归来做到这一点,以便我可以简化它。

2 个答案:

答案 0 :(得分:0)

假设您的数据的行为如下:

RowNum:           Position:
  0                   1
  1                  2 3
  2                 4 5 6

然后,您可以利用一个事实,即左边的Position等于其上方的位置加上RowNum,而右边的Position等于其上方的位置加上RowNum加1。因此,您可以构建一个递归算法使用这样的事实:

public static void main(String[] args) {
  int maxRows = 3;
  paths(maxRows, 1, 1, "1");
}

/**
 * Recursive top to bottom depth first approach
 * 
 * @param maxRow Total number of rows to travel down.
 * @param rowNum The current row an iteration is on.
 * @param position The position number above the current iteration.
 * @param values The values so far along the path.
 */
public static void paths(int maxRow, int rowNum, int position, String values) {
  //You've hit the bottom so print the results
  if(rowNum >= maxRow) {
    System.out.println(values);
    return;
  }

  int nextRow = rowNum + 1;

  //Calculate position for left side branch, append it to values, and start next iteration
  int leftPosition = position + rowNum;
  String leftValues = values + " " + leftPosition;
  paths(maxRow, nextRow, leftPosition, leftValues);

  //Calculate position for right side branch, append it to values, and start next iteration
  int rightPosition = position + rowNum + 1;
  String rightValues = values + " " + rightPosition;
  paths(maxRow, nextRow, rightPosition, rightValues);
}

编辑:这是一个将所有内容存储在容器中的版本,并具有重载版本以简化用户实际需要的参数。

  public static void main(String[] args) {
    //Initializes the path function
    List<List<Integer>> allPaths = paths(4);
    System.out.println(allPaths);
  }

  /**
   * Recursively find all paths in a pyramid like node path. Depth first search.
   * <pre><code>
   * Row   Position     
   *  0        1       
   *  1       2 3     
   *  2      4 5 6    
   *  3     7 8 9 10 
   *  </code></pre>
   *  
   * @param maxDepth Total number of rows to travel down.
   * @return Collection of all the paths in their own collections.
   */
  public static List<List<Integer>> paths(int maxDepth) {
    List<List<Integer>> allPaths = new ArrayList<>();
    List<Integer> path = new ArrayList<>();
    path.add(1);
    paths(maxDepth, 1, 1, path, allPaths);
    return allPaths;
  }

  /**
   * Recursively find all paths in a pyramid like node path. Depth first search.
   *   
   * @param maxDepth Total number of rows to travel down.
   * @param currentDepth The current depth an iteration is on.
   * @param topPosition The position number above the current iteration.
   * @param currentPath The values so far along the path.
   * @param allPaths Container for all the paths when it reaches the end.
   */
  private static void paths(int maxDepth, int currentDepth, int topPosition, List<Integer> currentPath, List<List<Integer>> allPaths) {
    //You've hit the bottom so print the results
    if(currentDepth >= maxDepth) {
      allPaths.add(currentPath);
      return;
    }

    int nextDepth = currentDepth + 1;

    //Calculate position for left side branch, append it to values, and start it's branching iterations
    int leftPosition = topPosition + currentDepth;
    List<Integer> leftArray = new ArrayList<>(currentPath);
    leftArray.add(leftPosition);
    paths(maxDepth, nextDepth, leftPosition, leftArray, allPaths);

   //Calculate position for right side branch, append it to values, and start it's branching iterations
    int rightPosition = topPosition + currentDepth + 1;
    List<Integer> rightArray = new ArrayList<>(currentPath);
    rightArray.add(rightPosition);
    paths(maxDepth, nextDepth, rightPosition, rightArray, allPaths);
  }

答案 1 :(得分:0)

要注意的是,行n中节点r的两个孩子分别是n + rn + r + 1。话虽如此,您可以构建一个相当简单的递归。 (对不起,您必须自己转换为Java!)

const paths = (levels, node = 1, row = 1, res = [[1]]) => levels < 2
  ? res
  : [
      ... paths (levels - 1, node + row, row + 1, res .map ((path) => [...path, node + row])),
      ... paths (levels - 1, node + row + 1, row + 1, res .map ((path) => [...path, node + row + 1]))
    ]


const results = paths (4)

console.log (
  results.map (JSON.stringify) .join ('\n')
)

会有2 ^ n个结果,所以我不想尝试50个级别!


更新

这是一种更简洁的编写递归的方法:

const last = (xs) => xs[xs.length - 1];

const paths = (levels, row = 1, res = [[1]]) => levels < 2
  ? res
  : paths (
      levels - 1, 
      row + 1, 
      res.flatMap(xs => [[...xs, last(xs) + row], [...xs, last(xs) + row + 1]])
    )


const results = paths (4)

console.log (
  results.map (JSON.stringify) .join ('\n')
)

这是相同的算法,只是编写递归的一种更简洁的方法。我们接受较深的级别数,然后默认为第一级别的行号(1)和结果([[1]])。递归从级别中减去一个,在行中添加一个,然后通过为该行中的每个条目创建两个条目来计算下一行的结果,其中一个附加最后一个值加行号,另一个附加一个比最后一个值加上行号。这比第一种方法更干净。