Leetcode動態規劃(2) 中等)

2021-10-06 14:29:02 字數 3893 閱讀 7632

簡單記錄刷題的過程(大佬勿噴)

一和零多維0-1揹包問題: 把題目給定的 0 的數量看成乙個揹包, 1的數量看成另乙個揹包,把陣列中的每乙個字串看成一件件商品,統計每乙個字串 0 和 1的數量,動態規劃填表

狀態轉移方程:dp[i][j] = max(dp[i][j],1+dp[i-count0][j-count1]),其中 dp[i][j]為使用 i個 0 和 j 個 1能表示字串的最大數量,count0 為陣列中每個字串中 0 的數量, count1為陣列中每個字串 1 的數量

class

solution

int dp[m+1]

[n+1];

memset

(dp,0,

sizeof

(int)*

(m+1)*

(n+1))

;for

(int i =

0; i

//01揹包,每個資料只能取一次

//倒序迴圈,避免資料被重複選擇

for(

int k = m; k>=count1;k--)}

}return dp[m]

[n];}}

;

分割等和子集

思路:題意是判斷是否能將乙個陣列分割成元素和相同的子集,那麼自然可以想到陣列的元素總和必須是偶數,否則無法一分為二。題目轉化為從陣列中找出一些元素讓它們的和等於陣列總和的一半(固定的值),因此可以想到利用 0-1揹包的思想解題,把固定和看成揹包的容量(直接套模板)

class

solution

if(sum%2==

1)int temp = sum/2;

int dp[temp+1]

;memset

(dp,0,

sizeof

(int)*

(temp+1)

);dp[0]

=true

;for

(int i =

0; i

return dp[temp];}

};

目標和

class

solution

if(sum

(s+sum)%2

==1)int val =

(s+sum)/2

;int dp[val+1]

;memset

(dp,0,

sizeof

(int)*

(val+1)

);//注意初始化

dp[0]

=1;//初始狀態:總和等於 0 的方案數(因為可以乙個都不取,因此方案數等於1)

for(

int i =

0; i

size()

;i++)}

return dp[val];}

};

零錢兌換

這道題可以看成是完全揹包問題,注意一些小的區別(1)原始完全揹包問題要求不超過,但是本題是恰好等於amount(2)題目求的是總價值最少,但是完全揹包問題是求總價值最大

思路:以coins = [1,2,5],amount = 11為例,f(i)表示湊成金額為 i 所需要的最少硬幣數

因此,f[j] = min(1 + f[j - coins[i]],f[j]) i = [0, coins.size() - 1] (注意:前提是硬幣的面值要小於當前的金額,否則無法使用,且剩餘的面值也要能夠湊出來),根據狀態方程就可以(直接套用完全揹包的模板)解題,因為要求最小值,所以dp初始化時要用盡量大的值

class

solution

int dp[amount+1]

;//注意不能用memset(dp,int_max,sizeof(int)*(amount+1))否則會溢位,得不到想要的結果

for(

int k =

0; k

1; k++

) dp[0]

=0;for

(int i =

0; i

size()

;i++)}

return dp[amount]

==99999?-

1:dp[amount];}

};

零錢兌換 ii

(是「零錢兌換」一題的變種,求的是方案數)所以 狀態方程改為求和而不是最小值,注意陣列初始化為0,初始狀態:amount等於 0 的方案數(因為可以乙個都不取,因此方案數等於1)(跟上面「目標和」一題求0-1揹包的方案數也很相似)

class

solution

}return dp[amount];}

};

單詞拆分

思路:用dp[i] 表示子串 s[0…i] ,假設這段子串可以被拆分,並且拆分以後的單詞落在 給定的字典 中,而且子串後面的單詞s[i+1…s.size()]也落在給定的字典中,即可判斷 dp[i]為真。因此通過不斷更新 dp 陣列來實現上述過程,最終dp[len]的值為真or 假即為所求最終結果。

注意初始狀態 dp[0]為true,因為如果給定的字串本身就在給定的字典裡面了,就可以直接判斷為真,而不必再進行 j 的遞增尋找 dp 的狀態了。

一些知識點:

1.c++的substr函式的用法:

例如:string s(「12345abcd」);

string a = s.substr(0,5); //獲得字串s中從第0位開始的長度為5的字串

輸出的結果是 「12345」

2.c++中vector使用find函式:不同於map、set、multiset、multimap,vector本身是沒有find這個方法,即不能使用 .find()呼叫,而是依靠標頭檔案algorithm來實現find函式。

形式是:find(a.begin(),a.end(),value)

解題的思路:

class

solution

int len = s.

size()

; vector<

bool

>

dp(len+1,

false);

dp[0]

=true

;for

(int i =

1; i<=len; i++)}

}return dp[len];}

};

組合總和 ⅳ

這道題跟前面的零錢兌換 ii很相似,兩者的區別是本題是順序不同的序列被視作不同的組合,即,視為兩種組合方式。因此,對於有順序的揹包問題時,方法可以改為以target為外迴圈,以陣列元素的作為內迴圈,狀態轉移方程為dp[i] = dp[i-nums[0]] + dp[i-nums[1] + dp[i-nums[2]]+……dp[i-nums[len-1]],len 為nums 陣列的長度

(如果想知道有順序和沒順序的揹包問題兩者之間的區別,不妨演算一遍,**下面附上我的演算過程)

class

solution

; */

unsigned

long

long dp[target+1]

;memset

(dp,0,

sizeof

(unsigned

long

long)*

(target+1)

);dp[0]

=1;for

(int i =

1; i<=target; i++)}

return dp[target];}

};

Leetcode 打家劫舍II(中等)動態規劃

題目描述 你是乙個專業的小偷,計畫偷竊沿街的房屋,每間房內都藏有一定的現金。這個地方所有的房屋都圍成一圈,這意味著第乙個房屋和最後乙個房屋是緊挨著的。同時,相鄰的房屋裝有相互連通的防盜系統,如果兩間相鄰的房屋在同一晚上被小偷闖入,系統會自動報警。給定乙個代表每個房屋存放金額的非負整數陣列,計算你在不...

LeetCode 中等 動態規劃 硬幣面值

硬幣。給定數量不限的硬幣,幣值為25分 10分 5分和1分,編寫 計算n分有幾種表示法。結果可能會很大,你需要將結果模上1000000007 示例1 輸入 n 5 輸出 2 解釋 有兩種方式可以湊成總金額 5 55 1 1 1 1 1 示例2 輸入 n 10 輸出 4 解釋 有四種方式可以湊成總金額...

動態規劃中等題

在排序陣列中查詢元素的第乙個和最後乙個位置 class solution def searchrange self,nums list int target int list int if not nums return 1,1 first index self.firstk nums,target...