mirror of
				https://github.com/krahets/hello-algo.git
				synced 2025-11-04 22:28:40 +08:00 
			
		
		
		
	Add comparison between iteration and recursion.
Fix the figure of tail recursion. Fix two links.
This commit is contained in:
		@ -17,6 +17,26 @@ int recur(int n) {
 | 
				
			|||||||
    return n + res;
 | 
					    return n + res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 使用迭代模拟递归 */
 | 
				
			||||||
 | 
					int forLoopRecur(int n) {
 | 
				
			||||||
 | 
					    // 使用一个显式的栈来模拟系统调用栈
 | 
				
			||||||
 | 
					    stack<int> stack;
 | 
				
			||||||
 | 
					    int res = 0;
 | 
				
			||||||
 | 
					    // 递:递归调用
 | 
				
			||||||
 | 
					    for (int i = n; i > 0; i--) {
 | 
				
			||||||
 | 
					        // 通过“入栈操作”模拟“递”
 | 
				
			||||||
 | 
					        stack.push(i);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // 归:返回结果
 | 
				
			||||||
 | 
					    while (!stack.empty()) {
 | 
				
			||||||
 | 
					        // 通过“出栈操作”模拟“归”
 | 
				
			||||||
 | 
					        res += stack.top();
 | 
				
			||||||
 | 
					        stack.pop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // res = 1+2+3+...+n
 | 
				
			||||||
 | 
					    return res;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 尾递归 */
 | 
					/* 尾递归 */
 | 
				
			||||||
int tailRecur(int n, int res) {
 | 
					int tailRecur(int n, int res) {
 | 
				
			||||||
    // 终止条件
 | 
					    // 终止条件
 | 
				
			||||||
@ -45,6 +65,9 @@ int main() {
 | 
				
			|||||||
    res = recur(n);
 | 
					    res = recur(n);
 | 
				
			||||||
    cout << "\n递归函数的求和结果 res = " << res << endl;
 | 
					    cout << "\n递归函数的求和结果 res = " << res << endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res = forLoopRecur(n);
 | 
				
			||||||
 | 
					    cout << "\n使用迭代模拟递归求和结果 res = " << res << endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res = tailRecur(n, 0);
 | 
					    res = tailRecur(n, 0);
 | 
				
			||||||
    cout << "\n尾递归函数的求和结果 res = " << res << endl;
 | 
					    cout << "\n尾递归函数的求和结果 res = " << res << endl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -8,7 +8,7 @@ package chapter_computational_complexity;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
public class iteration {
 | 
					public class iteration {
 | 
				
			||||||
    /* for 循环 */
 | 
					    /* for 循环 */
 | 
				
			||||||
    public static int forLoop(int n) {
 | 
					    static int forLoop(int n) {
 | 
				
			||||||
        int res = 0;
 | 
					        int res = 0;
 | 
				
			||||||
        // 循环求和 1, 2, ..., n-1, n
 | 
					        // 循环求和 1, 2, ..., n-1, n
 | 
				
			||||||
        for (int i = 1; i <= n; i++) {
 | 
					        for (int i = 1; i <= n; i++) {
 | 
				
			||||||
@ -18,7 +18,7 @@ public class iteration {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* while 循环 */
 | 
					    /* while 循环 */
 | 
				
			||||||
    public static int whileLoop(int n) {
 | 
					    static int whileLoop(int n) {
 | 
				
			||||||
        int res = 0;
 | 
					        int res = 0;
 | 
				
			||||||
        int i = 1; // 初始化条件变量
 | 
					        int i = 1; // 初始化条件变量
 | 
				
			||||||
        // 循环求和 1, 2, ..., n-1, n
 | 
					        // 循环求和 1, 2, ..., n-1, n
 | 
				
			||||||
@ -30,7 +30,7 @@ public class iteration {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* while 循环(两次更新) */
 | 
					    /* while 循环(两次更新) */
 | 
				
			||||||
    public static int whileLoopII(int n) {
 | 
					    static int whileLoopII(int n) {
 | 
				
			||||||
        int res = 0;
 | 
					        int res = 0;
 | 
				
			||||||
        int i = 1; // 初始化条件变量
 | 
					        int i = 1; // 初始化条件变量
 | 
				
			||||||
        // 循环求和 1, 4, ...
 | 
					        // 循环求和 1, 4, ...
 | 
				
			||||||
@ -44,7 +44,7 @@ public class iteration {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* 双层 for 循环 */
 | 
					    /* 双层 for 循环 */
 | 
				
			||||||
    public static String nestedForLoop(int n) {
 | 
					    static String nestedForLoop(int n) {
 | 
				
			||||||
        StringBuilder res = new StringBuilder();
 | 
					        StringBuilder res = new StringBuilder();
 | 
				
			||||||
        // 循环 i = 1, 2, ..., n-1, n
 | 
					        // 循环 i = 1, 2, ..., n-1, n
 | 
				
			||||||
        for (int i = 1; i <= n; i++) {
 | 
					        for (int i = 1; i <= n; i++) {
 | 
				
			||||||
 | 
				
			|||||||
@ -6,9 +6,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
package chapter_computational_complexity;
 | 
					package chapter_computational_complexity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.Stack;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class recursion {
 | 
					public class recursion {
 | 
				
			||||||
    /* 递归 */
 | 
					    /* 递归 */
 | 
				
			||||||
    public static int recur(int n) {
 | 
					    static int recur(int n) {
 | 
				
			||||||
        // 终止条件
 | 
					        // 终止条件
 | 
				
			||||||
        if (n == 1)
 | 
					        if (n == 1)
 | 
				
			||||||
            return 1;
 | 
					            return 1;
 | 
				
			||||||
@ -18,8 +20,27 @@ public class recursion {
 | 
				
			|||||||
        return n + res;
 | 
					        return n + res;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* 使用迭代模拟递归 */
 | 
				
			||||||
 | 
					    static int forLoopRecur(int n) {
 | 
				
			||||||
 | 
					        // 使用一个显式的栈来模拟系统调用栈
 | 
				
			||||||
 | 
					        Stack<Integer> stack = new Stack<>();
 | 
				
			||||||
 | 
					        int res = 0;
 | 
				
			||||||
 | 
					        // 递:递归调用
 | 
				
			||||||
 | 
					        for (int i = n; i > 0; i--) {
 | 
				
			||||||
 | 
					            // 通过“入栈操作”模拟“递”
 | 
				
			||||||
 | 
					            stack.push(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // 归:返回结果
 | 
				
			||||||
 | 
					        while (!stack.isEmpty()) {
 | 
				
			||||||
 | 
					            // 通过“出栈操作”模拟“归”
 | 
				
			||||||
 | 
					            res += stack.pop();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // res = 1+2+3+...+n
 | 
				
			||||||
 | 
					        return res;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* 尾递归 */
 | 
					    /* 尾递归 */
 | 
				
			||||||
    public static int tailRecur(int n, int res) {
 | 
					    static int tailRecur(int n, int res) {
 | 
				
			||||||
        // 终止条件
 | 
					        // 终止条件
 | 
				
			||||||
        if (n == 0)
 | 
					        if (n == 0)
 | 
				
			||||||
            return res;
 | 
					            return res;
 | 
				
			||||||
@ -28,7 +49,7 @@ public class recursion {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* 斐波那契数列:递归 */
 | 
					    /* 斐波那契数列:递归 */
 | 
				
			||||||
    public static int fib(int n) {
 | 
					    static int fib(int n) {
 | 
				
			||||||
        // 终止条件 f(1) = 0, f(2) = 1
 | 
					        // 终止条件 f(1) = 0, f(2) = 1
 | 
				
			||||||
        if (n == 1 || n == 2)
 | 
					        if (n == 1 || n == 2)
 | 
				
			||||||
            return n - 1;
 | 
					            return n - 1;
 | 
				
			||||||
@ -46,6 +67,9 @@ public class recursion {
 | 
				
			|||||||
        res = recur(n);
 | 
					        res = recur(n);
 | 
				
			||||||
        System.out.println("\n递归函数的求和结果 res = " + res);
 | 
					        System.out.println("\n递归函数的求和结果 res = " + res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        res = forLoopRecur(n);
 | 
				
			||||||
 | 
					        System.out.println("\n使用迭代模拟递归求和结果 res = " + res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        res = tailRecur(n, 0);
 | 
					        res = tailRecur(n, 0);
 | 
				
			||||||
        System.out.println("\n尾递归函数的求和结果 res = " + res);
 | 
					        System.out.println("\n尾递归函数的求和结果 res = " + res);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,23 @@ def recur(n: int) -> int:
 | 
				
			|||||||
    return n + res
 | 
					    return n + res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def for_loop_recur(n: int) -> int:
 | 
				
			||||||
 | 
					    """使用迭代模拟递归"""
 | 
				
			||||||
 | 
					    # 使用一个显式的栈来模拟系统调用栈
 | 
				
			||||||
 | 
					    stack = []
 | 
				
			||||||
 | 
					    res = 0
 | 
				
			||||||
 | 
					    # 递:递归调用
 | 
				
			||||||
 | 
					    for i in range(n, 0, -1):
 | 
				
			||||||
 | 
					        # 通过“入栈操作”模拟“递”
 | 
				
			||||||
 | 
					        stack.append(i)
 | 
				
			||||||
 | 
					    # 归:返回结果
 | 
				
			||||||
 | 
					    while stack:
 | 
				
			||||||
 | 
					        # 通过“出栈操作”模拟“归”
 | 
				
			||||||
 | 
					        res += stack.pop()
 | 
				
			||||||
 | 
					    # res = 1+2+3+...+n
 | 
				
			||||||
 | 
					    return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def tail_recur(n, res):
 | 
					def tail_recur(n, res):
 | 
				
			||||||
    """尾递归"""
 | 
					    """尾递归"""
 | 
				
			||||||
    # 终止条件
 | 
					    # 终止条件
 | 
				
			||||||
@ -42,6 +59,9 @@ if __name__ == "__main__":
 | 
				
			|||||||
    res = recur(n)
 | 
					    res = recur(n)
 | 
				
			||||||
    print(f"\n递归函数的求和结果 res = {res}")
 | 
					    print(f"\n递归函数的求和结果 res = {res}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    res = for_loop_recur(n)
 | 
				
			||||||
 | 
					    print(f"\n使用迭代模拟递归求和结果 res = {res}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    res = tail_recur(n, 0)
 | 
					    res = tail_recur(n, 0)
 | 
				
			||||||
    print(f"\n尾递归函数的求和结果 res = {res}")
 | 
					    print(f"\n尾递归函数的求和结果 res = {res}")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							| 
		 Before Width: | Height: | Size: 83 KiB After Width: | Height: | Size: 84 KiB  | 
@ -525,13 +525,15 @@
 | 
				
			|||||||
    [class]{}-[func]{tailRecur}
 | 
					    [class]{}-[func]{tailRecur}
 | 
				
			||||||
    ```
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
两种递归的过程对比如下图所示。
 | 
					尾递归的执行过程如下图所示。对比普通递归和尾递归,求和操作的执行点是不同的。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
- **普通递归**:求和操作是在“归”的过程中执行的,每层返回后都要再执行一次求和操作。
 | 
					- **普通递归**:求和操作是在“归”的过程中执行的,每层返回后都要再执行一次求和操作。
 | 
				
			||||||
- **尾递归**:求和操作是在“递”的过程中执行的,“归”的过程只需层层返回。
 | 
					- **尾递归**:求和操作是在“递”的过程中执行的,“归”的过程只需层层返回。
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!!! tip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    请注意,许多编译器或解释器并不支持尾递归优化。例如,Python 默认不支持尾递归优化,因此即使函数是尾递归形式,但仍然可能会遇到栈溢出问题。
 | 
					    请注意,许多编译器或解释器并不支持尾递归优化。例如,Python 默认不支持尾递归优化,因此即使函数是尾递归形式,但仍然可能会遇到栈溢出问题。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### 递归树
 | 
					### 递归树
 | 
				
			||||||
@ -629,3 +631,108 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
- 从算法角度看,搜索、排序、回溯、分治、动态规划等许多重要算法策略都直接或间接地应用这种思维方式。
 | 
					- 从算法角度看,搜索、排序、回溯、分治、动态规划等许多重要算法策略都直接或间接地应用这种思维方式。
 | 
				
			||||||
- 从数据结构角度看,递归天然适合处理链表、树和图的相关问题,因为它们非常适合用分治思想进行分析。
 | 
					- 从数据结构角度看,递归天然适合处理链表、树和图的相关问题,因为它们非常适合用分治思想进行分析。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 两者对比
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					总结以上内容,如下表所示,迭代和递归在实现、性能和适用性上有所不同。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<p align="center"> 表 <id>   迭代与递归特点对比 </p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|          | 迭代                                   | 递归                                                         |
 | 
				
			||||||
 | 
					| -------- | -------------------------------------- | ------------------------------------------------------------ |
 | 
				
			||||||
 | 
					| 实现方式 | 循环结构                               | 函数调用自身                                                 |
 | 
				
			||||||
 | 
					| 时间效率 | 效率通常较高,无函数调用开销           | 每次函数调用都会产生开销                                     |
 | 
				
			||||||
 | 
					| 内存使用 | 通常使用固定大小的内存空间             | 累积函数调用可能使用大量的栈帧空间                           |
 | 
				
			||||||
 | 
					| 适用问题 | 适用于简单循环任务,代码直观、可读性好 | 适用于子问题分解,如树、图、分治、回溯等,代码结构简洁、清晰 |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					!!! tip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    如果感觉以下内容理解困难,可以在读完“栈”章节后再来复习。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					那么,迭代和递归具有什么内在联系呢?以上述的递归函数为例,求和操作在递归的“归”阶段进行。这意味着最初被调用的函数实际上是最后完成其求和操作的,**这种工作机制与栈的“先入后出”原则是异曲同工的**。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					事实上,“调用栈”和“栈帧空间”这类递归术语已经暗示了递归与栈之间的密切关系。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. **递**:当函数被调用时,系统会在“调用栈”上为该函数分配新的栈帧,用于存储函数的局部变量、参数、返回地址等数据。
 | 
				
			||||||
 | 
					2. **归**:当函数完成执行并返回时,对应的栈帧会从“调用栈”上被移除,恢复之前函数的执行环境。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					因此,**我们可以使用一个显式的栈来模拟调用栈的行为**,从而将递归转化为迭代形式:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "Python"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```python title="recursion.py"
 | 
				
			||||||
 | 
					    [class]{}-[func]{for_loop_recur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "C++"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```cpp title="recursion.cpp"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "Java"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```java title="recursion.java"
 | 
				
			||||||
 | 
					    [class]{recursion}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "C#"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```csharp title="recursion.cs"
 | 
				
			||||||
 | 
					    [class]{recursion}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "Go"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```go title="recursion.go"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "Swift"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```swift title="recursion.swift"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "JS"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```javascript title="recursion.js"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "TS"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```typescript title="recursion.ts"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "Dart"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```dart title="recursion.dart"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "Rust"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```rust title="recursion.rs"
 | 
				
			||||||
 | 
					    [class]{}-[func]{for_loop_recur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "C"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```c title="recursion.c"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					=== "Zig"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```zig title="recursion.zig"
 | 
				
			||||||
 | 
					    [class]{}-[func]{forLoopRecur}
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					观察以上代码,当递归被转换为迭代后,代码变得更加复杂了。尽管迭代和递归在很多情况下可以互相转换,但也不一定值得这样做,有以下两点原因。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- 转化后的代码可能更加难以理解,可读性更差。
 | 
				
			||||||
 | 
					- 对于某些复杂问题,模拟系统调用栈的行为可能非常困难。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					总之,**选择迭代还是递归取决于特定问题的性质**。在编程实践中,权衡两者的优劣并根据情境选择合适的方法是至关重要的。
 | 
				
			||||||
 | 
				
			|||||||
@ -209,7 +209,7 @@ git clone https://github.com/krahets/hello-algo.git
 | 
				
			|||||||
从总体上看,我们可以将学习数据结构与算法的过程划分为三个阶段。
 | 
					从总体上看,我们可以将学习数据结构与算法的过程划分为三个阶段。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
1. **算法入门**。我们需要熟悉各种数据结构的特点和用法,学习不同算法的原理、流程、用途和效率等方面内容。
 | 
					1. **算法入门**。我们需要熟悉各种数据结构的特点和用法,学习不同算法的原理、流程、用途和效率等方面内容。
 | 
				
			||||||
2. **刷算法题**。建议从热门题目开刷,如[剑指 Offer](https://leetcode.cn/problem-list/xb9nqhhg/)和[LeetCode Hot 100](https://leetcode.cn/problem-list/2cktkvj/),先积累至少 100 道题目,熟悉主流的算法问题。初次刷题时,“知识遗忘”可能是一个挑战,但请放心,这是很正常的。我们可以按照“艾宾浩斯遗忘曲线”来复习题目,通常在进行 3-5 轮的重复后,就能将其牢记在心。
 | 
					2. **刷算法题**。建议从热门题目开刷,如[剑指 Offer](https://leetcode.cn/studyplan/coding-interviews/)和[LeetCode Hot 100](https://leetcode.cn/studyplan/top-100-liked/),先积累至少 100 道题目,熟悉主流的算法问题。初次刷题时,“知识遗忘”可能是一个挑战,但请放心,这是很正常的。我们可以按照“艾宾浩斯遗忘曲线”来复习题目,通常在进行 3-5 轮的重复后,就能将其牢记在心。
 | 
				
			||||||
3. **搭建知识体系**。在学习方面,我们可以阅读算法专栏文章、解题框架和算法教材,以不断丰富知识体系。在刷题方面,可以尝试采用进阶刷题策略,如按专题分类、一题多解、一解多题等,相关的刷题心得可以在各个社区找到。
 | 
					3. **搭建知识体系**。在学习方面,我们可以阅读算法专栏文章、解题框架和算法教材,以不断丰富知识体系。在刷题方面,可以尝试采用进阶刷题策略,如按专题分类、一题多解、一解多题等,相关的刷题心得可以在各个社区找到。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
如下图所示,本书内容主要涵盖“第一阶段”,旨在帮助你更高效地展开第二和第三阶段的学习。
 | 
					如下图所示,本书内容主要涵盖“第一阶段”,旨在帮助你更高效地展开第二和第三阶段的学习。
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user