簡單記錄刷題的過程(大佬勿噴)
一和零多維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...