經典dp--搶家奪舍系列之GO寫法
搶家奪舍系列–經典dp系列GO寫法
house-robber
首先我們從比較簡單的角度來做:
- 判斷狀態:題目只有兩種狀態,也就是偷或者不偷,所以我們可以建立一個二維的陣列,並用0表示不偷,1表示偷
- 陣列的長度:這個實際上就是你房子的數量;
- 狀態轉移方程:當你在第i家時,選擇不偷時,dp[i][0]就是選擇dp[i-1]中最大的一個,選擇偷的話,前面那家肯定不能偷,因此dp[i][1] = nums[i] + dp[i-1][0]。所以有狀態轉移方程:
- 最後Max(dp[len - 1][0], dp[len - 1][1])就是結果啦
// accept code 程式碼一
func rob(nums []int) int {
length := len(nums)
if length < 1 {
return 0
}
dp := make([][2]int, length)
dp[0][1] = nums[0]
dp[0][0] = 0
for i := 1; i < length; i++ {
dp[i][0] = max(dp[i-1][0], dp[i-1][1])
dp[i][1] = dp[i-1][0] + nums[i]
}
return max(dp[length-1][0], dp[length-1][1])
}
func max(values ...int) int {
maxValue := math.MinInt32
for _, value := range values {
if value > maxValue {
maxValue = value;
}
}
return maxValue;
}
值得注意的是,這個程式碼可以簡化成一維陣列,dp[i]表示當前i房子後能偷到的最多錢,所以我們可以利用i i-1 and i-2 來表示鄰避關係,也就是說有狀態轉移方程:
//程式碼二
func rob(nums []int) int {
length := len(nums)
if length < 1 {
return 0
}
if length == 1 {
return nums[0];
}
dp := make([]int, length)
dp[0] = nums[0]
dp[1] = nums[1]
for i := 2; i < length; i++ {
dp[i] = max(dp[i-2]+nums[i], dp[i-1])
}
return dp[length-1]
}
func max(values ...int) int {
maxValue := math.MinInt32
for _, value := range values {
if value > maxValue {
maxValue = value;
}
}
return maxValue;
}
通過程式碼二我們可以進一步優化空間複雜度,因為我們可見不論怎樣,dp狀態轉移方程只跟
i i-1 and i-2 這三者有關,所以我們可以只使用三個變數dp, dp1, dp2來進行更新:
dp1 = dp2
dp2 = dp
因此有程式碼:
//程式碼三
func rob(nums []int) int {
length := len(nums)
if length < 1 {
return 0
}
dp1 := 0 //初始化為0 邊界需要判斷清晰
dp2 := 0
dp := 0
for i := 0; i < length; i++ {
dp = max(dp1 + nums[i], dp2)
dp1 = dp2
dp2 = dp
}
return dp
}
func max(values ...int) int {
maxValue := math.MinInt32
for _, value := range values {
if value > maxValue {
maxValue = value;
}
}
return maxValue;
}
house-robber-II
這個題目有限制就是陣列是為一個環形陣列,因此我們可以分為兩種情況考慮,當選第一個來偷時,就不再考慮最後一個房子;當選最後一個來偷時,就不再考慮第一個房子;最後對於這兩種情況選出一個最大值出來就好啦。
所以改改上面的程式碼就好了:
func rob(nums []int) int {
length := len(nums)
if length < 1 {
return 0;
} else if length == 1 {
return nums[0];
}
return max(subRob(nums,0, length - 2), subRob(nums, 1, length - 1))
}
func subRob(nums []int, st, ed int) int {
dp := 0
dp1 := 0
dp2 := 0
for i := st; i <= ed; i++ {
dp = max(dp1 + nums[i], dp2)
dp1 = dp2
dp2 = dp
}
return dp
}
func max(a, b int) int {
if a < b {
return b
}
return a
}
house-robber-III
這個是採用樹的形式,同理,對於某一個節點我們可偷可不偷,我們儲存兩個狀態,rob and noRob。 所以有計算公式:
func rob(root *TreeNode) int {
if root == nil {
return 0
}
noRob, rob := getResult(root);
return Max(noRob, rob);
}
func getResult(root *TreeNode) (a, b int) {
if root == nil{
return 0, 0
}
left0, left1 := getResult(root.Left)
right0, right1 := getResult(root.Right)
rob := root.Val + left0 + right0
// 可偷子節點或者不偷子節點,選最大的那個情況就好
noRob := Max(left0, left1) + Max(right0, right1)
return noRob, rob
}
func getResult(root *TreeNode) (noRob, rob int) {
if root == nil{
return 0, 0
}
left0, left1 := getResult(root.Left)
right0, right1 := getResult(root.Right)
rob = root.Val + left0 + right0
noRob = Max(left0, left1) + Max(right0, right1)
return
}
func Max(a,b int) int {
if a < b {
return b
} else {
return a
}
}
相關文章
- Go系列之反射Go反射
- OpenCV之C++經典案例OpenCVC++
- Go語言入門經典第18章Go
- 奪命雷公狗-----React---24--小案例之react經典案例todos(單條任務的刪除)React
- 經典排序之選擇排序(Java)排序Java
- 經典問題之「分支預測」
- 67.Java-資源搶奪案例(使用synchronized)Javasynchronized
- 清華尹成帶你實戰GO案例(42)Go 經典hello worldGo
- css經典佈局系列一——垂直居中佈局CSS
- 續寫經典!《魔法門之英雄無敵:王朝》先鋒測試今日開啟
- 2023前端二面經典手寫面試題前端面試題
- JavaScript設計模式經典之代理模式JavaScript設計模式
- jquery經典例項之回到頂部jQuery
- 《Flutter 入門經典》之“Flutter 入門 ”Flutter
- Go語言庫系列之emailGoAI
- Go編譯原理系列4(語法分析)Go編譯原理語法分析
- Go編譯原理系列3(詞法分析)Go編譯原理詞法分析
- 深度學習經典卷積神經網路之AlexNet深度學習卷積神經網路
- 【前端詞典】繼承(二) - 回的八種寫法前端繼承
- css經典佈局系列二——等分等高佈局CSS
- (一)文字分類經典模型之CNN篇文字分類模型CNN
- TCP通訊之經典問題解決TCP
- 重拾經典,每日一讀之--《屈原全集》
- Java入門系列之重寫Java
- SICP 經典
- Go編譯原理系列2(詞法分析&語法分析基礎)Go編譯原理詞法分析語法分析
- 關於利用go實現非同步讀寫的寫法分享Go非同步
- 小白經典CNN論文復現系列(一):LeNet1989CNN
- shell指令碼之if elif寫法指令碼
- Python 入門之經典函式例項(二)Python函式
- 機器學習經典演算法之EM機器學習演算法
- 機器學習經典演算法之KNN機器學習演算法KNN
- Go資料結構系列之 Array and AliceGo資料結構
- 人工智慧研究:經典推理和非經典推理人工智慧
- Go 的搶佔式排程Go
- 德國經濟學家預測:巴西德國世界盃奪冠機會最大
- 騰訊前端一面經典手寫面試題合集前端面試題
- Spring 經典教程Spring