Bài toán
Link đến bài toán: 746. Min Cost Climbing Stairs
Phân tích
Ta có thể dễ dàng lập công thức đệ quy để giải bài toán này:
f(n) = min(f(n - 1), f(n - 2)) + cost[n]
Tuy nhiên, sao phải dùng đệ quy khi ta có thể dùng dynamic programming? (=^OwO^=)
Ta có thể dùng một mảng dp
để lưu lại kết quả của các bài toán con đã được giải.
Với dp[i]
là chi phí nhỏ nhất để đi đến bậc thang thứ i
.
dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
Độ phức tạp của giải thuật là O(n)
, và độ phức tạp không gian là O(n)
.
Nếu như quan sát kĩ hơn, ta thấy rằng ta chỉ cần lưu lại hai giá trị dp[i - 1]
và dp[i - 2]
thôi.
Lúc này, độ phức tạp không gian sẽ là O(1)
.
Giải thuật
Đệ quy
1. Nếu `n == 0` hoặc `n == 1` thì `f(n) = cost[n]`.
2. Nếu `n > 1` thì `f(n) = min(f(n - 1), f(n - 2)) + cost[n]`.
Dynamic programming
1. Khởi tạo mảng `dp` với `dp[0] = cost[0]` và `dp[1] = cost[1]`.
2. Với `i` từ `2` đến `len(cost) - 1`:
1. `dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]`.
3. Trả về `min(dp[len(cost) - 1], dp[len(cost) - 2])`.
Dynamic programming (không dùng mảng)
1. Khởi tạo `dp0 = cost[0]` và `dp1 = cost[1]`.
2. Với `i` từ `2` đến `len(cost) - 1`:
1. `dp2 = min(dp1, dp0) + cost[i]`.
2. `dp0 = dp1`.
3. `dp1 = dp2`.
3. Trả về `min(dp1, dp0)`.
Code
Đệ quy
func minCostClimbingStairs(cost []int) int {
n := len(cost)
if n == 0 || n == 1 {
return cost[n - 1]
}
return min(minCostClimbingStairs(cost[:n - 1]), minCostClimbingStairs(cost[:n - 2])) + cost[n - 1]
}
Dynamic programming
func minCostClimbingStairs(cost []int) int {
n := len(cost)
dp := make([]int, n)
dp[0] = cost[0]
dp[1] = cost[1]
for i := 2; i < n; i++ {
dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i]
}
return min(dp[n - 1], dp[n - 2])
}
Dynamic programming (không dùng mảng)
func minCostClimbingStairs(cost []int) int {
n := len(cost)
dp0 := cost[0]
dp1 := cost[1]
for i := 2; i < n; i++ {
dp2 := min(dp1, dp0) + cost[i]
dp0 = dp1
dp1 = dp2
}
return min(dp1, dp0)
}