mirror of
https://github.com/krahets/hello-algo.git
synced 2025-11-02 12:58:42 +08:00
Sort the coding languages by applications. (#721)
This commit is contained in:
@ -14,12 +14,12 @@
|
||||
|
||||
本题的目标是求解方案数量,**我们可以考虑通过回溯来穷举所有可能性**。具体来说,将爬楼梯想象为一个多轮选择的过程:从地面出发,每轮选择上 $1$ 阶或 $2$ 阶,每当到达楼梯顶部时就将方案数量加 $1$ ,当越过楼梯顶部时就将其剪枝。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="climbing_stairs_backtrack.java"
|
||||
[class]{climbing_stairs_backtrack}-[func]{backtrack}
|
||||
```python title="climbing_stairs_backtrack.py"
|
||||
[class]{}-[func]{backtrack}
|
||||
|
||||
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
|
||||
[class]{}-[func]{climbing_stairs_backtrack}
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@ -30,12 +30,20 @@
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="climbing_stairs_backtrack.py"
|
||||
[class]{}-[func]{backtrack}
|
||||
```java title="climbing_stairs_backtrack.java"
|
||||
[class]{climbing_stairs_backtrack}-[func]{backtrack}
|
||||
|
||||
[class]{}-[func]{climbing_stairs_backtrack}
|
||||
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_backtrack.cs"
|
||||
[class]{climbing_stairs_backtrack}-[func]{backtrack}
|
||||
|
||||
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@ -46,6 +54,14 @@
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_backtrack.swift"
|
||||
[class]{}-[func]{backtrack}
|
||||
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="climbing_stairs_backtrack.js"
|
||||
@ -62,38 +78,6 @@
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_backtrack.c"
|
||||
[class]{}-[func]{backtrack}
|
||||
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_backtrack.cs"
|
||||
[class]{climbing_stairs_backtrack}-[func]{backtrack}
|
||||
|
||||
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_backtrack.swift"
|
||||
[class]{}-[func]{backtrack}
|
||||
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_backtrack.zig"
|
||||
[class]{}-[func]{backtrack}
|
||||
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="climbing_stairs_backtrack.dart"
|
||||
@ -110,6 +94,22 @@
|
||||
[class]{}-[func]{climbing_stairs_backtrack}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_backtrack.c"
|
||||
[class]{}-[func]{backtrack}
|
||||
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_backtrack.zig"
|
||||
[class]{}-[func]{backtrack}
|
||||
|
||||
[class]{}-[func]{climbingStairsBacktrack}
|
||||
```
|
||||
|
||||
## 方法一:暴力搜索
|
||||
|
||||
回溯算法通常并不显式地对问题进行拆解,而是将问题看作一系列决策步骤,通过试探和剪枝,搜索所有可能的解。
|
||||
@ -136,12 +136,12 @@ $$
|
||||
|
||||
观察以下代码,它和标准回溯代码都属于深度优先搜索,但更加简洁。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="climbing_stairs_dfs.java"
|
||||
[class]{climbing_stairs_dfs}-[func]{dfs}
|
||||
```python title="climbing_stairs_dfs.py"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
|
||||
[class]{}-[func]{climbing_stairs_dfs}
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@ -152,12 +152,20 @@ $$
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="climbing_stairs_dfs.py"
|
||||
[class]{}-[func]{dfs}
|
||||
```java title="climbing_stairs_dfs.java"
|
||||
[class]{climbing_stairs_dfs}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbing_stairs_dfs}
|
||||
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dfs.cs"
|
||||
[class]{climbing_stairs_dfs}-[func]{dfs}
|
||||
|
||||
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@ -168,6 +176,14 @@ $$
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dfs.swift"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="climbing_stairs_dfs.js"
|
||||
@ -184,38 +200,6 @@ $$
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dfs.c"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dfs.cs"
|
||||
[class]{climbing_stairs_dfs}-[func]{dfs}
|
||||
|
||||
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dfs.swift"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dfs.zig"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="climbing_stairs_dfs.dart"
|
||||
@ -232,6 +216,22 @@ $$
|
||||
[class]{}-[func]{climbing_stairs_dfs}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dfs.c"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dfs.zig"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFS}
|
||||
```
|
||||
|
||||
下图展示了暴力搜索形成的递归树。对于问题 $dp[n]$ ,其递归树的深度为 $n$ ,时间复杂度为 $O(2^n)$ 。指数阶属于爆炸式增长,如果我们输入一个比较大的 $n$ ,则会陷入漫长的等待之中。
|
||||
|
||||

|
||||
@ -247,12 +247,12 @@ $$
|
||||
1. 当首次计算 $dp[i]$ 时,我们将其记录至 `mem[i]` ,以便之后使用。
|
||||
2. 当再次需要计算 $dp[i]$ 时,我们便可直接从 `mem[i]` 中获取结果,从而避免重复计算该子问题。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="climbing_stairs_dfs_mem.java"
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
|
||||
```python title="climbing_stairs_dfs_mem.py"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
|
||||
[class]{}-[func]{climbing_stairs_dfs_mem}
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@ -263,12 +263,20 @@ $$
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="climbing_stairs_dfs_mem.py"
|
||||
[class]{}-[func]{dfs}
|
||||
```java title="climbing_stairs_dfs_mem.java"
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbing_stairs_dfs_mem}
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dfs_mem.cs"
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
|
||||
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@ -279,6 +287,14 @@ $$
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dfs_mem.swift"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="climbing_stairs_dfs_mem.js"
|
||||
@ -295,38 +311,6 @@ $$
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dfs_mem.c"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dfs_mem.cs"
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
|
||||
|
||||
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dfs_mem.swift"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dfs_mem.zig"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="climbing_stairs_dfs_mem.dart"
|
||||
@ -343,6 +327,22 @@ $$
|
||||
[class]{}-[func]{climbing_stairs_dfs_mem}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dfs_mem.c"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dfs_mem.zig"
|
||||
[class]{}-[func]{dfs}
|
||||
|
||||
[class]{}-[func]{climbingStairsDFSMem}
|
||||
```
|
||||
|
||||
观察下图,**经过记忆化处理后,所有重叠子问题都只需被计算一次,时间复杂度被优化至 $O(n)$** ,这是一个巨大的飞跃。
|
||||
|
||||

|
||||
@ -355,10 +355,10 @@ $$
|
||||
|
||||
由于动态规划不包含回溯过程,因此只需使用循环迭代实现,无须使用递归。在以下代码中,我们初始化一个数组 `dp` 来存储子问题的解,它起到了记忆化搜索中数组 `mem` 相同的记录作用。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="climbing_stairs_dp.java"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
|
||||
```python title="climbing_stairs_dp.py"
|
||||
[class]{}-[func]{climbing_stairs_dp}
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@ -367,10 +367,16 @@ $$
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="climbing_stairs_dp.py"
|
||||
[class]{}-[func]{climbing_stairs_dp}
|
||||
```java title="climbing_stairs_dp.java"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dp.cs"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@ -379,6 +385,12 @@ $$
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dp.swift"
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="climbing_stairs_dp.js"
|
||||
@ -391,30 +403,6 @@ $$
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dp.c"
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dp.cs"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dp.swift"
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dp.zig"
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="climbing_stairs_dp.dart"
|
||||
@ -427,6 +415,18 @@ $$
|
||||
[class]{}-[func]{climbing_stairs_dp}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dp.c"
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dp.zig"
|
||||
[class]{}-[func]{climbingStairsDP}
|
||||
```
|
||||
|
||||
下图模拟了以上代码的执行过程。
|
||||
|
||||

|
||||
@ -443,10 +443,10 @@ $$
|
||||
|
||||
细心的你可能发现,**由于 $dp[i]$ 只与 $dp[i-1]$ 和 $dp[i-2]$ 有关,因此我们无须使用一个数组 `dp` 来存储所有子问题的解**,而只需两个变量滚动前进即可。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="climbing_stairs_dp.java"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
|
||||
```python title="climbing_stairs_dp.py"
|
||||
[class]{}-[func]{climbing_stairs_dp_comp}
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@ -455,10 +455,16 @@ $$
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="climbing_stairs_dp.py"
|
||||
[class]{}-[func]{climbing_stairs_dp_comp}
|
||||
```java title="climbing_stairs_dp.java"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dp.cs"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@ -467,6 +473,12 @@ $$
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dp.swift"
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="climbing_stairs_dp.js"
|
||||
@ -479,30 +491,6 @@ $$
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dp.c"
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="climbing_stairs_dp.cs"
|
||||
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="climbing_stairs_dp.swift"
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dp.zig"
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="climbing_stairs_dp.dart"
|
||||
@ -515,6 +503,18 @@ $$
|
||||
[class]{}-[func]{climbing_stairs_dp_comp}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="climbing_stairs_dp.c"
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="climbing_stairs_dp.zig"
|
||||
[class]{}-[func]{climbingStairsDPComp}
|
||||
```
|
||||
|
||||
观察以上代码,由于省去了数组 `dp` 占用的空间,因此空间复杂度从 $O(n)$ 降低至 $O(1)$ 。
|
||||
|
||||
在动态规划问题中,当前状态往往仅与前面有限个状态有关,这时我们可以只保留必要的状态,通过“降维”来节省内存空间。**这种空间优化技巧被称为“滚动变量”或“滚动数组”**。
|
||||
|
||||
Reference in New Issue
Block a user