Skip to content

feat: add solutions to lc problem: No.0746 #3252

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Jul 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
212 changes: 203 additions & 9 deletions solution/0700-0799/0746.Min Cost Climbing Stairs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,177 @@ tags:

<!-- solution:start -->

### 方法一:动态规划
### 方法一:记忆化搜索

我们设计一个函数 $\textit{dfs}(i)$,表示从第 $i$ 个阶梯开始爬楼梯所需要的最小花费。那么答案为 $\min(\textit{dfs}(0), \textit{dfs}(1))$。

函数 $\textit{dfs}(i)$ 的执行过程如下:

- 如果 $i \ge \textit{len(cost)}$,表示当前位置已经超过了楼梯顶部,不需要再爬楼梯,返回 $0$;
- 否则,我们可以选择爬 $1$ 级楼梯,花费为 $\textit{cost}[i]$,然后递归调用 $\textit{dfs}(i + 1)$;也可以选择爬 $2$ 级楼梯,花费为 $\textit{cost}[i]$,然后递归调用 $\textit{dfs}(i + 2)$;
- 返回两种方案中的最小花费。

为了避免重复计算,我们使用记忆化搜索的方法,将已经计算过的结果保存在数组或哈希表中。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $\textit{cost}$ 的长度。

<!-- tabs:start -->

#### Python3

```python
class Solution:
def minCostClimbingStairs(self, cost: List[int]) -> int:
@cache
def dfs(i: int) -> int:
if i >= len(cost):
return 0
return cost[i] + min(dfs(i + 1), dfs(i + 2))

return min(dfs(0), dfs(1))
```

#### Java

```java
class Solution {
private Integer[] f;
private int[] cost;

public int minCostClimbingStairs(int[] cost) {
this.cost = cost;
f = new Integer[cost.length];
return Math.min(dfs(0), dfs(1));
}

private int dfs(int i) {
if (i >= cost.length) {
return 0;
}
if (f[i] == null) {
f[i] = cost[i] + Math.min(dfs(i + 1), dfs(i + 2));
}
return f[i];
}
}
```

#### C++

```cpp
class Solution {
public:
int minCostClimbingStairs(vector<int>& cost) {
int n = cost.size();
int f[n];
memset(f, -1, sizeof(f));
auto dfs = [&](auto&& dfs, int i) -> int {
if (i >= n) {
return 0;
}
if (f[i] < 0) {
f[i] = cost[i] + min(dfs(dfs, i + 1), dfs(dfs, i + 2));
}
return f[i];
};
return min(dfs(dfs, 0), dfs(dfs, 1));
}
};
```

#### Go

```go
func minCostClimbingStairs(cost []int) int {
n := len(cost)
f := make([]int, n)
for i := range f {
f[i] = -1
}
var dfs func(int) int
dfs = func(i int) int {
if i >= n {
return 0
}
if f[i] < 0 {
f[i] = cost[i] + min(dfs(i+1), dfs(i+2))
}
return f[i]
}
return min(dfs(0), dfs(1))
}
```

#### TypeScript

```ts
function minCostClimbingStairs(cost: number[]): number {
const n = cost.length;
const f: number[] = Array(n).fill(-1);
const dfs = (i: number): number => {
if (i >= n) {
return 0;
}
if (f[i] < 0) {
f[i] = cost[i] + Math.min(dfs(i + 1), dfs(i + 2));
}
return f[i];
};
return Math.min(dfs(0), dfs(1));
}
```

#### Rust

```rust
impl Solution {
pub fn min_cost_climbing_stairs(cost: Vec<i32>) -> i32 {
let n = cost.len();
let mut f = vec![-1; n];

fn dfs(i: usize, cost: &Vec<i32>, f: &mut Vec<i32>, n: usize) -> i32 {
if i >= n {
return 0;
}
if f[i] < 0 {
let next1 = dfs(i + 1, cost, f, n);
let next2 = dfs(i + 2, cost, f, n);
f[i] = cost[i] + next1.min(next2);
}
f[i]
}

dfs(0, &cost, &mut f, n).min(dfs(1, &cost, &mut f, n))
}
}
```

#### JavaScript

```js
function minCostClimbingStairs(cost) {
const n = cost.length;
const f = Array(n).fill(-1);
const dfs = i => {
if (i >= n) {
return 0;
}
if (f[i] < 0) {
f[i] = cost[i] + Math.min(dfs(i + 1), dfs(i + 2));
}
return f[i];
};
return Math.min(dfs(0), dfs(1));
}
```

<!-- tab:end -->

<!-- solution:end -->

<!-- solution:start -->

### 方法二:动态规划

我们定义 $f[i]$ 表示到达第 $i$ 个阶梯所需要的最小花费,初始时 $f[0] = f[1] = 0$,答案即为 $f[n]$。

Expand All @@ -77,9 +247,7 @@ $$

最终的答案即为 $f[n]$。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 `cost` 的长度。

我们注意到,状态转移方程中的 $f[i]$ 只和 $f[i - 1]$ 与 $f[i - 2]$ 有关,因此我们可以使用两个变量 $f$ 和 $g$ 交替地记录 $f[i - 2]$ 和 $f[i - 1]$ 的值,这样空间复杂度可以优化到 $O(1)$。
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 是数组 $\textit{cost}$ 的长度。

<!-- tabs:start -->

Expand Down Expand Up @@ -167,13 +335,28 @@ impl Solution {
}
```

#### JavaScript

```js
function minCostClimbingStairs(cost) {
const n = cost.length;
const f = Array(n + 1).fill(0);
for (let i = 2; i <= n; ++i) {
f[i] = Math.min(f[i - 1] + cost[i - 1], f[i - 2] + cost[i - 2]);
}
return f[n];
}
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- solution:start -->

### 方法二
### 方法三:动态规划(空间优化)

我们注意到,状态转移方程中的 $f[i]$ 只和 $f[i - 1]$ 与 $f[i - 2]$ 有关,因此我们可以使用两个变量 $f$ 和 $g$ 交替地记录 $f[i - 2]$ 和 $f[i - 1]$ 的值,这样空间复杂度可以优化到 $O(1)$。

<!-- tabs:start -->

Expand Down Expand Up @@ -237,12 +420,11 @@ func minCostClimbingStairs(cost []int) int {

```ts
function minCostClimbingStairs(cost: number[]): number {
let a = 0,
b = 0;
let [f, g] = [0, 0];
for (let i = 1; i < cost.length; ++i) {
[a, b] = [b, Math.min(a + cost[i - 1], b + cost[i])];
[f, g] = [g, Math.min(f + cost[i - 1], g + cost[i])];
}
return b;
return g;
}
```

Expand All @@ -262,6 +444,18 @@ impl Solution {
}
```

#### JavaScript

```js
function minCostClimbingStairs(cost) {
let [f, g] = [0, 0];
for (let i = 1; i < cost.length; ++i) {
[f, g] = [g, Math.min(f + cost[i - 1], g + cost[i])];
}
return g;
}
```

<!-- tabs:end -->

<!-- solution:end -->
Expand Down
Loading
Loading