简体   繁体   English

以递归方式按升序打印所有数字组合(长度 n 在 1 到 9 之间)

[英]Print all cominations of numbers in ascending order recursively (with length n between 1 and 9)

I want to print all number combinations that are in ascending order.我想打印所有按升序排列的数字组合。 The output should go like: 012, 013, 014, ..., 789 for n = 3. I tried to solve it using recursion, however I'm having the StackOverflowError. output 应该 go 像:012,013,014,...,789 for n = 3。我尝试使用递归来解决它,但是我遇到了 StackOverflowError。 So it means it never reaches the result.所以这意味着它永远不会达到结果。 Here is my code so far:到目前为止,这是我的代码:


public class Main {
  public static void main(String[] args) {

    int[] a = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0};
    print_combinations(a, 0, 3);
  }

  static void print_combinations(int[] a, int index, int n) {
    if (n > 0 && n < 10) {
      if (index == n - 1) {
        if (is_ascending(a, n)) {
          System.out.print(Arrays.toString(a));
          System.out.print(", ");
        }
        if (!has_ended(a, n)) {
          print_combinations(a, 0, n);
        }
      } else {
        while (a[index] <= 9 - n + index - 1) {
          print_combinations(a, index + 1, n);
          if (index < n - 1 && a[index] == 9 - n + index - 1) {
            a[index + 1] = 0;
          }
          a[index]++;
        }
      }
    }
  }

  static boolean has_ended(int[] a, int n) {
    int ctr = 0;
    while (ctr < n) {
      if (a[ctr] != 10 - n + ctr) {
        return false;
      } else {
        ctr++;
      }
    }
    return true;
  }

  static boolean is_ascending(int[] a, int n) {
    int ctr = 0;

    while (ctr < n - 1) {
      if (a[ctr] >= a[ctr + 1]) {
        return false;
      }
      ctr++;
    }
    return true;
  }
}```

print_combinations is being called recursively by itself hundreds of thousands of times until it overflows. print_combinations 本身被递归调用数十万次,直到它溢出。

a[index]++;

is never reached in print_combinations due to index constantly being reset to 0 after the.has_ended check.由于在 .has_ended 检查之后索引不断被重置为 0,因此在 print_combinations 中永远不会达到。

This means that all but the print_combinations call in the while loop are unreachable.这意味着除了 while 循环中的 print_combinations 调用之外的所有调用都无法访问。

My personal recommendation is to just increment an integer like the example below and just use a bit of funky programming to check the ascending bit, just modifying your code to make it work but there are probably better ways.我个人的建议是像下面的示例一样增加 integer 并使用一些时髦的编程来检查升序位,只需修改代码以使其工作,但可能有更好的方法。

public class TestCode {

    public static void main(String[] args) {

        int a = 0;
        int n = 4;
        TestCode test = new TestCode();
        while(Integer.toString(a).length() < n-1){
            a++;
    
        }
        while(Integer.toString(a).length() <= n){
            test.print_combinations(a, 0, n);
            a++;
        }
    }

    public void print_combinations(int a, int index, int n) {
        char[] print = new char[n];
        char[] test = Integer.toString(a).toCharArray();
        if(test.length < n && test.length >= n - 1){
            print = new char[test.length+1];
            for(int x = 0; x <= test.length; x++){
                if(x == 0){
                    print[x] = '0';
                }else{
                    print[x] = test[x-1];
                }
            }
            if(this.is_ascending(print, n)){
                System.out.println(new String(print));
            }
        }else if(this.is_ascending(test, n)){
            System.out.println(new String(test));
        }
    }

    public boolean is_ascending(char[] a, int n) {
      int ctr = 0;

      while (ctr < n - 1) {
        if (Character.getNumericValue(a[ctr]) >= Character.getNumericValue(a[ctr + 1])) {
      return false;
        }
        ctr++;
      }
      return true;
    }
}

Alternatively, if you're absolutely hellbent on using arrays, do the exact opposite, check for descending and when you print it out use something like或者,如果您绝对热衷于使用 arrays,请执行完全相反的操作,检查降序并在打印时使用类似

System.out.println("" + a[index +2] + a[index +1] + a[index])

This will grab an array of [9,7,4] and print it out as "479"这将获取 [9,7,4] 的数组并将其打印为“479”

Doing it this way will drastically ease your interactions with arrays and reduce the need for recursions since you're working from the front of the array and make troubleshooting far easier.这样做将大大简化您与 arrays 的交互,并减少对递归的需求,因为您是从阵列的前端工作,并使故障排除更加容易。

There are these issues in your code:您的代码中存在以下问题:

  • The base case is not when if (index == n - 1) , because then you still need to populate a[index] will different digits.基本情况不是if (index == n - 1) ,因为那样你仍然需要填充a[index]将不同的数字。 The base case is when if (index == n) .基本情况是if (index == n)

  • Once the base case is treated, you should not make even deeper recursive calls, as you do with the if (,has_ended(a, n)) block.一旦处理了基本情况,就不应像使用if (,has_ended(a, n))那样进行更深层次的递归调用。 No, the principle of recursion is that you backtrack once you have reached the end of a search path, so you simply need to return.不,递归的原理是一旦到达搜索路径的尽头就回溯,因此只需返回即可。 The caller will deal with other variations.调用者将处理其他变体。 This if block should be removed.这个if块应该被删除。

  • The while loop ends too soon. while循环结束得太快了。 Its condition should not be a[index] <= 9 - n + index - 1 , but a[index] <= 9 - n + index + 1 .它的条件不应该是a[index] <= 9 - n + index - 1 ,而是a[index] <= 9 - n + index + 1

  • The if condition inside that loop is testing the wrong array value, and comparing with the wrong limit.该循环内的if条件正在测试错误的数组值,并与错误的限制进行比较。 It should not be a[index] == 9 - n + index - 1 , but a[index + 1] == 9 - n + index + 3 .它不应该是a[index] == 9 - n + index - 1 ,而是a[index + 1] == 9 - n + index + 3

  • With Arrays.toString(a) you'll get all 10 entries of a instead of the first n of them.使用Arrays.toString(a)您将获得a的所有 10 个条目,而不是其中的前n个条目。 You could do Arrays.toString(Arrays.copyOfRange(a, 0, n)) .你可以做Arrays.toString(Arrays.copyOfRange(a, 0, n))

With those fixes your code will work:通过这些修复,您的代码将起作用:

  static void print_combinations(int[] a, int index, int n) {
    if (n > 0 && n < 10) {
      if (index == n) {
        if (is_ascending(a, n)) {
          System.out.print(Arrays.toString(Arrays.copyOfRange(a, 0, n)));
          System.out.print(", ");
        }
      } else {
        while (a[index] <= 9 - n + index + 1) {
          print_combinations(a, index + 1, n);
          if (index < n - 1 && a[index + 1] == 9 - n + index + 3) {
            a[index + 1] = 0;
          }
          a[index]++;
        }
      }
    }
  }

There are more elegant ways to achieve the desired output, but at least this shows you where your code had issues.有更优雅的方法可以实现所需的 output,但至少这可以告诉您代码哪里有问题。

Here is a version that does not allocate 10 array entries, but first defines n and then uses that for a dynamic length for the array.这是一个不分配 10 个数组条目的版本,但首先定义n ,然后将其用于数组的动态长度。 Also, the iteration over the different digits can be done with a for loop, and you can also add logic to not start each time at 0, but at one more than the digit at the left.此外,不同数字的迭代可以使用for循环来完成,您还可以添加逻辑以不每次都从 0 开始,而是比左边的数字多一个。 This way you don't need the check whether the array is ascending, as it is then guaranteed.这样你就不需要检查数组是否在升序,因为它是保证的。

    public static void main(String[] args) {
        int n = 3;
        int[] a = new int[n];
        print_combinations(a, 0, n);
    }

    static void print_combinations(int[] a, int index, int n) {
        if (index == n) {
            System.out.print(Arrays.toString(a));
            System.out.print(", ");
        } else {
            int first = index > 0 ? a[index - 1] + 1 : 0;
            int last = 10 - n + index;
            for (int digit = first; digit <= last; digit++) {
                a[index] = digit;
                print_combinations(a, index + 1, n);
            }
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM