How to break out of a recursion


Java中,我们用break跳出循环,那跳出递归怎么办?举例如下:


需求1:给定一整数数组input,打印其所有可能的组合sub,用递归来实现的代码如下:

//递归函数
public static void recursion(int[] input, int pick, int start, int count, int[] sub) {
    if (count == pick) {
        System.out.print(Arrays.toString(sub));
        return;
    }
    for (int i = start; i < input.length; ++i) {
        sub[count++] = input[i];
        recursion(input, pick, ++start, count, sub);
        --count;
    }
}

public static void main(String[] args) {
    int[] inputArray = new int[] { 9, 7, 2 };
    for (int i = 1; i <= inputArray.length; i++) {
        int[] sub = new int[i];
        recursion(inputArray, i, 0, 0, sub);
    }
}

打印结果如下,共7个组合:

[9],[7],[2],[9, 7],[9, 2],[7, 2],[9, 7, 2]

需求2:给定一整数数组input,如:7,9,4,2,如果可以使用3个简单运算符(+,-,=)使得至少有一个表达式成立(如7+4-2=9或9-7=4-2),则打印YES和该表达式(用"+"号连接),否则打印NO。

分析和简化需求:

  • 考虑使用递归枚举所有可能的表达式;
  • 题干中"至少有一个表达式成立",也就是说,如果存在这样的表达式,找到一个即刻break跳出递归,并打印YES和该表达式,否则打印NO
  • 变换表达式的形式,如:7+4=9+2或(7+4)-(9+2)=0,也就是说,跳出递归的条件是:如果数组中存在n个整数(n>=1),使得这n个整数的和为原数组和的一半,即2* Sum(n)=Sum(input)

需求分析清楚后,代码就很好写了,在需求1中代码上增强如下:

//递归函数
public static boolean recursion(Integer[] input, int pick, int start, int count, Integer[] sub) {
    if (count == pick) {
        if (2 * sum(sub) == sum(input)) {
            return true;
        }
        return false;
    }
    boolean found = false;
    for (int i = start; i < input.length; ++i) {
        sub[count++] = input[i];
        if (recursion(input, pick, ++start, count, sub)) {
            found = true;
            break;
        }
        --count;
    }
    return found;
}

// 求和
public static int sum(Integer[] input) {
    Integer total = 0;
    for (Integer each : input) {
        total += each;
    }
    return total;
}

// 重写数组差 by index
public static Integer[] subtraction(Integer[] full, Integer[] sub) {
    List<Integer> fullList = new ArrayList<Integer>(Arrays.asList(full));
    for (int i = 0; i < sub.length; i++) {
        for (int j = 0; j < fullList.size(); j++) {
            if (sub[i].equals(fullList.get(j))) {
                fullList.remove(j);
                break;
            }
        }
    }
    return fullList.toArray(new Integer[]{});
}

// 使用"+"连接数组元素
public static String array2expression(Integer[] arr) {
    String expression = "";
    for (Integer str : arr) {
        expression += str + "+";
    }
    return expression.substring(0, expression.length() - 1);
}

public static void main(String[] args) {
    Integer[] inputArray = new Integer[] { 9, 7, 2 };
    for (int i = 1; i <= inputArray.length / 2; i++) {
        Integer[] branch = new Integer[i];
        if (recursion(inputArray, i, 0, 0, branch)){
            Integer[] sub = subtraction(inputArray, branch);
            print(String.format("%s = %s", array2expression(branch), array2expression(sub)));
            break;
        }
    }
}

打印结果:

9 = 7+2

总结,我们能学到什么:

  • 通过给递归函数定义返回值,在递归过程中判断该返回值可结束递归
  • 分析和简化需求,如:变换表达式的形式,找出需求的关键所在,如:2*Sum(n) = Sum(input)

就酱,您有任何问题或建议, 请给我写邮件


Yinwer /
Published under (CC) BY-NC-SA