[course03] 05 Recursion

Recursion

A recursive subrouting must:

  • hava a base case

  • have a general case

  • reach the base case after a finite (limited) number of calls to itself

递归代码的思路

以Factorial阶层函数为例

第一步 - 明确你的函数的功能

先明确的搞清楚函数到底是用来做什么的,函数的主要功能。函数需要传入一个阶层的数。

FUNCTION Factorial(n : INTEGER) RETURNS INTEGER 

ENDFUNCTION

第二步 - 寻找递归结束条件

所谓递归,就是会在函数内部代码中,调用这个函数本身,所以,我们必须要找出递归的结束条件,不然的话,会一直调用自己,进入无底洞。也就是说,我们需要找出当参数为啥时,递归结束,之后直接把结果返回。

阶层函数计算到最后一个1为止

FUNCTION Factorial(n : INTEGER) RETURNS INTEGER 
    IF n = 0
        THEN 
            Result ← 1   // This is the base case
    ENDIF 
ENDFUNCTION

第三步 - 找出函数的等价关系式

第三步我们要不断缩小参数的范围,缩小之后,我们可以通过一些辅助的变量或者操作,使原函数的结果不变。要找到一个等价关系式,每次都可以直接使用等价调用。

FUNCTION Factorial(n : INTEGER) RETURNS INTEGER
    IF n = 0
        THEN 
            Result ← 1   // This is the base case
        ELSE
            Result ← n * Factorial(n – 1) // This is the general case
    ENDIF 
    RETURN Result
ENDFUNCTION   

什么是递归

进一步剖析「递归」,先有「递」再有「归」,「递」的意思是将问题拆解成子问题来解决, 子问题再拆解成子子问题,...,直到被拆解的子问题无需再拆分成更细的子问题(即可以求解),「归」是说最小的子问题解决了,那么它的上一层子问题也就解决了,上一层的子问题解决了,上上层子问题自然也就解决了,....,直到最开始的问题解决,文字说可能有点抽象,那我们就以阶层 f(6) 为例来看下它的「递」和「归」。

在书上的例子上,我们把递称为 base case,归称为 Recursive。

Example 1 factorial

Given n of 1 or more, return the factorial of n, which is n * (n-1) * (n-2) ... 1. Compute the result recursively (without loops).

  • factorial(1) → 1

  • factorial(2) → 2

  • factorial(3) → 6

public int factorial(int n) {
  if (n == 1){
    return n;
  }
  return n * factorial(n - 1);
}

Example 2 fibonacci

The fibonacci sequence is a famous bit of mathematics, and it happens to have a recursive definition. The first two values in the sequence are 0 and 1 (essentially 2 base cases). Each subsequent value is the sum of the previous two values, so the whole sequence is: 0, 1, 1, 2, 3, 5, 8, 13, 21 and so on. Define a recursive fibonacci(n) method that returns the nth fibonacci number, with n=0 representing the start of the sequence.

  • fibonacci(0) → 0

  • fibonacci(1) → 1

  • fibonacci(2) → 1

public int fibonacci(int n) {
  if (n == 2){
    return 1;
  }
  else if (n == 1){
    return 1;
  }
  else if (n ==0){
    return 0;
  }
  return fibonacci(n - 1) + fibonacci(n - 2);
}

Example 3 count7

Given a non-negative int n, return the count of the occurrences of 7 as a digit, so for example 717 yields 2. (no loops). Note that mod (%) by 10 yields the rightmost digit (126 % 10 is 6), while divide (/) by 10 removes the rightmost digit (126 / 10 is 12).

  • count7(717) → 2

  • count7(7) → 1

  • count7(123) → 0

public int count7(int n) {
  if (n <= 1){
    return 0;
  }
  if (n % 10 == 7){
    return 1 + count7(n/10);
  } else{
    return count7(n/10);
  }
}

Example 4 changeXY

Given a string, compute recursively (no loops) a new string where all the lowercase 'x' chars have been changed to 'y' chars.

  • changeXY("codex") → "codey"

  • changeXY("xxhixx") → "yyhiyy"

  • changeXY("xhixhix") → "yhiyhiy"

public String changeXY(String str) {
  if (str.length() == 0){
    return "";
  }
  if (str.startsWith("x")){
    return "y" + changeXY(str.substring(1));
  }else{
    return str.substring(0,1) + changeXY(str.substring(1));
  }
}

Example 5 count11

Given a string, compute recursively (no loops) the number of "11" substrings in the string. The "11" substrings should not overlap.

  • count11("11abc11") → 2

  • count11("abc11x11x11") → 3

  • count11("111") → 1

public int count11(String str) {
  if (str.length() <= 1){
    return 0;
  }
  if (str.startsWith("11")){
    return 1 + count11(str.substring(2));
  }else {
    return count11(str.substring(1));
  }
}

Example 6 array11

Given an array of ints, compute recursively the number of times that the value 11 appears in the array. We'll use the convention of considering only the part of the array that begins at the given index. In this way, a recursive call can pass index+1 to move down the array. The initial call will pass in index as 0.

  • array11([1, 2, 11], 0) → 1

  • array11([11, 11], 0) → 2

  • array11([1, 2, 3, 4], 0) → 0

public int array11(int[] nums, int index) {
  if (nums.length == index){
    return 0;
  }
  if (nums[index] == 11){
    return 1 + array11(nums, index + 1);
  }else{
    return array11(nums, index + 1);
  }
}

Why use index, how to delete an element in an array?

import java.util.Arrays;

public class DeleteElementInArray {
    public static int[] deleteElement(int[] arr, int index){
        int[] arr_new = new int[arr.length-1];
        for(int i=0;i<arr_new.length;i++){
            // 判断元素是否越界
            if (index < 0 || index >= arr.length) {
                throw new RuntimeException("元素越界... ");
            }
            if(i<index) {
                arr_new[i] = arr[i];
            }
            else {
                arr_new[i] = arr[i+1];
            }
        }
        return arr_new;
    }

    public static void main(String[] args) {
        int[] arr = {1,2,2,3,4,5,6,7};
        System.out.println(Arrays.toString(deleteElement(arr, 2)));
    }
}

Use ArrayList to rewite:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Count11ArrayList {
    public static int count11(ArrayList<Integer> arr){
        if (arr.size() == 0){
            return 0;
        }
        if (arr.get(0).equals(11)){
            arr.remove(0);
            return 1 + count11(arr);
        }else{
            arr.remove(0);
            return count11(arr);
        }
    }

    public static void main(String[] args) {
        int[] x = {1,2,11,5,11,11};
        List<Integer> xx = Arrays.stream(x).boxed().collect(Collectors.toList());
        System.out.println(count11(new ArrayList<Integer>(xx)));
    }
}

Last updated

Was this helpful?