Week 12 - Recursion

Outline

1. Examples of Recursion

 Factorial

 Recursion God vs Recursive Calls

 Handshake Problem

2.  Recursion Recipe(秘诀,处方)

 Base Case

 Recursive Step

 with Helper Method(辅助方法)

3.  More examples

 Fibonacci Number(斐波那契数列), The Twelve Days of Christmas, Subsequences

一、Algorithms Design Techniques

1. 递归是算法设计的工具

Recursion as a Tool for Algorithm Design

 递归是一种从代码实现过渡 (transition)到问题解决的关键技术。

2. 快速算法设计

Designing Fast Algorithms

(1)Divide-and-Conquer(分治法) = Divide + Delegate (Recursion) + Combine

        通过递归分解问题、委派任务,并合并结果

(2)Dynamic Programming(动态规划)= Recursion + Memoization

        结合递归与记忆化技术来提高效率

3. 旅行商问题

Travelling Salesman Problem

(1)目标是寻找访问所有城市的最短路径。

(2)穷举解法(Brute-force solution)时间复杂度为 O(n!),而动态规划降低为 O(n^2 * 2^n)。

因此所有城市对的关系总共有  n^2  组合。所有子集总数: 2^n 

4. Factorial 

Factorial fact(n) of a number n >= 0 is defined as follows

• fact(0) = 1

• fact(n) = n * fact(n-1)

fact(n) = n * n-1 * n-2 * ··· * 3 * 2 * 1

二、Recursion 

1. Recursion Code

 

 

2. Handshake Problem 

n个人在房间里,每个人都与其他人握手,递归公式为 handshake(n) = handshake(n-1) + (n-1)。

基础案例为 handshake(1) = 0

public static int handshake(int n) {

    // Base case

    if (n <= 1) {

        return 0;

    }

    // Recursive step

    return handshake(n - 1) + (n - 1);

}

• 假设 handshake(n-1) 能计算前 n-1 个人的握手次数。

• 第 n 个人需要与其他 n-1 个人握手,因此总握手次数为 handshake(n-1) + (n-1)。

3. Recipe for Recursion

递归的步骤

递归的核心思想是将问题分解为更小的子问题,并依赖子问题(smaller instances)的解来构建原始问题的解。

(1) Base Case

• 找到可以直接解决的最简单情况。(计算阶乘时,当n = 0时,直接返回 1)

(2) Recursive Step

• 尝试从几个例子中观察递归关系(recursive relation among instances)。

• 根据通用规律对n进行公式化(formulate generally for n),并依赖递归调用来解决较小的实例。

• 确保每次递归都能最终到达base case

递归结构就像俄罗斯套娃一样,每个问题都包含一个规模更小的子问题,直到遇到最小的情况(基础案例)

4. Rabbit Breeding Problem 

(1) 问题描述

• 假设一对兔子需要一个时间单位成熟并开始繁殖,每次繁殖都生出一对雄性和雌性兔子。

• 兔子永远不会死亡。

• 问题:在第n个时间单位后,兔子共有多少对?

(2) 解决方法

这实际上是斐波那契数列(Fibonacci Number)的应用。每个时间单位的兔子总数是前两期兔子总数之和:fibo(n) = fibo(n - 1) + fibo(n - 2)

(3) 递归公式

• 基础案例:

fibo(0) = 0

fibo(1) = 1

• 递归公式:

fibo(n) = fibo(n - 1) + fibo(n - 2)

5. Fibonacci Number Code

斐波那契数代码

public static int fibo(int n) {

    // Base case

    if (n == 0 || n == 1) {

        return n;

    }

    // Recursive step

    return fibo(n - 1) + fibo(n - 2);

}

6. The Twelve Days of Christmas Problem

问题描述:

• 在第n天,收到的礼物总数是前一天礼物总数加上当天新增的礼物数量。

• 问题:在第n天,共收到多少礼物?

递归公式:

基础案例

gifts(1) = 1

递归公式

gifts(n) = gifts(n-1) + n

public static int gifts(int n) {

    // Base case

    if (n == 1) {

        return 1;

    }

    // Recursive step

    return gifts(n - 1) + n;

}

如果 ,计算过程如下:

• 第 1 天:1 件礼物。

• 第 2 天:1(前一天)+ 2(当天)= 3 件。

• 第 3 天:3(前两天总数)+ 3(当天)= 6 件。

三、Subsequences Problem

子序列问题

 给定一个由字母 A-Z 或 a-z 组成的字符串,返回所有可能的子序列(Subsequences)。

 子序列是从字符串中选出的字母组成的,字母的顺序保持不变。

示例:subsequences("abc") 的输出为:abc, ab, bc, ac, a, b, c, ""。

注意点:

• 空字符串 "" 也是一个有效的子序列。

the trailing comma preceding the empty string "" 

1. 每个字母可以选择加入子序列,也可以不选择

2. 对于字符串 "abc":

• 选择第一个字母 "a":递归处理剩余字符串 "bc"。

• 不选择第一个字母:递归处理剩余字符串 "bc"。

3. 基础案例(Base Case):

• 当字符串为空时,子序列仅包含空字符串 ""。

4. 递归公式:

• 子序列 = 所有包含当前字母的子序列 + 所有不包含当前字母的子序列。

1. Helper Method 

private static String subseqHelper(String partialSubseq, String word) {

        if (word.isEmpty())

// base case

                return partialSubseq;

        else

// recursive step

        return subseqHelper(partialSubseq + word.charAt(0),word.substring(1)) + ","

+ subseqHelper(partialSubseq, word.substring(1));

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值