Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
119 changes: 51 additions & 68 deletions solution/0100-0199/0120.Triangle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,11 @@ tags:
我们定义 $f[i][j]$ 表示从三角形底部走到位置 $(i, j)$ 的最小路径和。这里的位置 $(i, j)$ 指的是三角形中第 $i$ 行第 $j$ 列(均从 $0$ 开始编号)的位置。那么我们有如下的状态转移方程:

$$
f[i][j] = \min(f[i + 1][j], f[i + 1][j + 1]) + triangle[i][j]
f[i][j] = \min(f[i + 1][j], f[i + 1][j + 1]) + \text{triangle}[i][j]
$$

答案即为 $f[0][0]$。

我们注意到,状态 $f[i][j]$ 仅与状态 $f[i + 1][j]$ 和状态 $f[i + 1][j + 1]$ 有关,因此我们可以使用一维数组代替二维数组,将空间复杂度从 $O(n^2)$ 降低至 $O(n)$。

时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 是三角形的行数。

更进一步,我们还可以直接复用 $triangle$ 作为 $f$ 数组,这样就无需再额外创建 $f$ 数组,空间复杂度降低至 $O(1)$。

<!-- tabs:start -->

#### Python3
Expand All @@ -105,13 +99,13 @@ class Solution:
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
int n = triangle.size();
int[] f = new int[n + 1];
int[][] f = new int[n + 1][n + 1];
for (int i = n - 1; i >= 0; --i) {
for (int j = 0; j <= i; ++j) {
f[j] = Math.min(f[j], f[j + 1]) + triangle.get(i).get(j);
f[i][j] = Math.min(f[i + 1][j], f[i + 1][j + 1]) + triangle.get(i).get(j);
}
}
return f[0];
return f[0][0];
}
}
```
Expand All @@ -123,14 +117,13 @@ class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
int n = triangle.size();
int f[n + 1];
memset(f, 0, sizeof(f));
for (int i = n - 1; ~i; --i) {
vector<vector<int>> f(n + 1, vector<int>(n + 1, 0));
for (int i = n - 1; i >= 0; --i) {
for (int j = 0; j <= i; ++j) {
f[j] = min(f[j], f[j + 1]) + triangle[i][j];
f[i][j] = min(f[i + 1][j], f[i + 1][j + 1]) + triangle[i][j];
}
}
return f[0];
return f[0][0];
}
};
```
Expand All @@ -140,13 +133,16 @@ public:
```go
func minimumTotal(triangle [][]int) int {
n := len(triangle)
f := make([]int, n+1)
f := make([][]int, n+1)
for i := range f {
f[i] = make([]int, n+1)
}
for i := n - 1; i >= 0; i-- {
for j := 0; j <= i; j++ {
f[j] = min(f[j], f[j+1]) + triangle[i][j]
f[i][j] = min(f[i+1][j], f[i+1][j+1]) + triangle[i][j]
}
}
return f[0]
return f[0][0]
}
```

Expand All @@ -155,13 +151,13 @@ func minimumTotal(triangle [][]int) int {
```ts
function minimumTotal(triangle: number[][]): number {
const n = triangle.length;
const f: number[] = Array(n + 1).fill(0);
for (let i = n - 1; ~i; --i) {
const f: number[][] = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0));
for (let i = n - 1; i >= 0; --i) {
for (let j = 0; j <= i; ++j) {
f[j] = Math.min(f[j], f[j + 1]) + triangle[i][j];
f[i][j] = Math.min(f[i + 1][j], f[i + 1][j + 1]) + triangle[i][j];
}
}
return f[0];
return f[0][0];
}
```

Expand All @@ -171,13 +167,13 @@ function minimumTotal(triangle: number[][]): number {
impl Solution {
pub fn minimum_total(triangle: Vec<Vec<i32>>) -> i32 {
let n = triangle.len();
let mut f = vec![0; n + 1];
let mut f = vec![vec![0; n + 1]; n + 1];
for i in (0..n).rev() {
for j in 0..=i {
f[j] = f[j].min(f[j + 1]) + triangle[i][j];
f[i][j] = f[i + 1][j].min(f[i + 1][j + 1]) + triangle[i][j];
}
}
f[0]
f[0][0]
}
}
```
Expand All @@ -188,7 +184,11 @@ impl Solution {

<!-- solution:start -->

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

我们注意到,状态 $f[i][j]$ 仅与状态 $f[i + 1][j]$ 和状态 $f[i + 1][j + 1]$ 有关,因此我们可以使用一维数组代替二维数组,将空间复杂度从 $O(n^2)$ 降低至 $O(n)$。

时间复杂度 $O(n^2)$,空间复杂度 $O(n)$。其中 $n$ 是三角形的行数。

<!-- tabs:start -->

Expand All @@ -210,14 +210,14 @@ class Solution:
```java
class Solution {
public int minimumTotal(List<List<Integer>> triangle) {
for (int i = triangle.size() - 2; i >= 0; --i) {
int n = triangle.size();
int[] f = new int[n + 1];
for (int i = n - 1; i >= 0; --i) {
for (int j = 0; j <= i; ++j) {
int x = triangle.get(i).get(j);
int y = Math.min(triangle.get(i + 1).get(j), triangle.get(i + 1).get(j + 1));
triangle.get(i).set(j, x + y);
f[j] = Math.min(f[j], f[j + 1]) + triangle.get(i).get(j);
}
}
return triangle.get(0).get(0);
return f[0];
}
}
```
Expand All @@ -228,12 +228,14 @@ class Solution {
class Solution {
public:
int minimumTotal(vector<vector<int>>& triangle) {
for (int i = triangle.size() - 2; ~i; --i) {
int n = triangle.size();
vector<int> f(n + 1, 0);
for (int i = n - 1; i >= 0; --i) {
for (int j = 0; j <= i; ++j) {
triangle[i][j] += min(triangle[i + 1][j], triangle[i + 1][j + 1]);
f[j] = min(f[j], f[j + 1]) + triangle[i][j];
}
}
return triangle[0][0];
return f[0];
}
};
```
Expand All @@ -242,25 +244,29 @@ public:

```go
func minimumTotal(triangle [][]int) int {
for i := len(triangle) - 2; i >= 0; i-- {
n := len(triangle)
f := make([]int, n+1)
for i := n - 1; i >= 0; i-- {
for j := 0; j <= i; j++ {
triangle[i][j] += min(triangle[i+1][j], triangle[i+1][j+1])
f[j] = min(f[j], f[j+1]) + triangle[i][j]
}
}
return triangle[0][0]
return f[0]
}
```

#### TypeScript

```ts
function minimumTotal(triangle: number[][]): number {
for (let i = triangle.length - 2; ~i; --i) {
const n = triangle.length;
const f: number[] = Array(n + 1).fill(0);
for (let i = n - 1; i >= 0; --i) {
for (let j = 0; j <= i; ++j) {
triangle[i][j] += Math.min(triangle[i + 1][j], triangle[i + 1][j + 1]);
f[j] = Math.min(f[j], f[j + 1]) + triangle[i][j];
}
}
return triangle[0][0];
return f[0];
}
```

Expand All @@ -269,13 +275,14 @@ function minimumTotal(triangle: number[][]): number {
```rust
impl Solution {
pub fn minimum_total(triangle: Vec<Vec<i32>>) -> i32 {
let mut triangle = triangle;
for i in (0..triangle.len() - 1).rev() {
let n = triangle.len();
let mut f = vec![0; n + 1];
for i in (0..n).rev() {
for j in 0..=i {
triangle[i][j] += triangle[i + 1][j].min(triangle[i + 1][j + 1]);
f[j] = f[j].min(f[j + 1]) + triangle[i][j];
}
}
triangle[0][0]
f[0]
}
}
```
Expand All @@ -284,28 +291,4 @@ impl Solution {

<!-- solution:end -->

<!-- solution:start -->

### 方法三

<!-- tabs:start -->

#### Python3

```python
class Solution:
def minimumTotal(self, triangle: List[List[int]]) -> int:
n = len(triangle)
for i in range(n - 2, -1, -1):
for j in range(i + 1):
triangle[i][j] = (
min(triangle[i + 1][j], triangle[i + 1][j + 1]) + triangle[i][j]
)
return triangle[0][0]
```

<!-- tabs:end -->

<!-- solution:end -->

<!-- problem:end -->
Loading
Loading