1049. 最後一塊石頭的重量 II
題目連結:1049. 最後一塊石頭的重量 II
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰最後一塊石頭的重量 II
日期:2024-10-10
想法:這這麼會是分割等和子集一類的問題。。。
Java程式碼如下:
class Solution {
public int lastStoneWeightII(int[] stones) {
if(stones == null || stones.length == 0) return 0;
int sum = 0;
for(int num : stones) {
sum += num;
}
int target = sum / 2;
int[] dp = new int[target + 1];
for(int i = 0; i < stones.length; i++) {
for(int j = target; j >= stones[i]; j--) {
dp[j] = Math.max(dp[j], dp[j - stones[i]] + stones[i]);
}
}
return sum - 2 * dp[target];
}
}
494. 目標和
題目連結:494. 目標和
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰目標和
日期:2024-10-10
想法:假設加法的總和為bagSize,那麼減法對應的總和就是sum - bagSize,所以要求的是 bagSize - (sum - bagSize) = target; bagSize = (target + sum) / 2
此時問題就轉化為,用nums裝滿容量為bagSize的揹包,有幾種方法。
- dp的意思是有多少種組合滿足,二維陣列dp[i][j]表示nums種0到i的數相加得到j的組合數為dp[i][j],
- 遞推公式:第一種情況dp[i - 1][j]表示不加上nums[i]這個數時能得到和為j的組合數,第二種情況要加上nums[i],先就得騰出j - nums[i]的空間,看此時dp[i - 1][j - nums[i]]有多少組合,這個組合數就是加上nums[i]總和為j的組合數。
3.初始化:初始化第一行第一列,第一行j剛好等於nums[0]時會有1種(要nums[0]),第一列的話如果nums[0]不是0,那麼就1種組合法(不要nums[0]),如果nums[0]是0的話就會麻煩點,那麼就2^1 = 2種組合法(不要nums[0],要nums[0]都行),第一列第二個如果也是0,就會有2^2 = 4種(不要nums[0],要nums[0],不要nums[1],要nums[1]都行),所以有多少個0,就有2多少次方個方法。
4.遍歷順序:上下左右,左右上下都行。
5.舉例推導dp陣列
Java程式碼如下:
//二維陣列
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for(int num : nums) {
sum += num;
}
if((sum + target) % 2 != 0) return 0;
if(Math.abs(target) > sum) return 0;
int bagSize = (sum + target) / 2;
int[][] dp = new int[nums.length][bagSize + 1];
int zeroN = 0;
if(nums[0] <= bagSize) dp[0][nums[0]] = 1;
for(int i = 0; i < nums.length; i++) {
if(nums[i] == 0) {
zeroN++;
}
dp[i][0] = (int) Math.pow(2, zeroN);
}
for(int i = 1; i < nums.length; i++) {
for(int j = 1; j <= bagSize; j++) {
if(j >= nums[i]) {
dp[i][j] = dp[i - 1][j] + dp[i - 1][j -nums[i]];
}else {
dp[i][j] = dp[i - 1][j];
}
}
}
return dp[nums.length - 1][bagSize];
}
}
//一維陣列
class Solution {
public int findTargetSumWays(int[] nums, int target) {
int sum = 0;
for(int num : nums) {
sum += num;
}
if((sum + target) % 2 != 0) return 0;
if(Math.abs(target) > sum) return 0;
int bagSize = (sum + target) / 2;
int[] dp = new int[bagSize + 1];
dp[0] = 1;
for(int i = 0; i < nums.length; i++) {
for(int j = bagSize; j >= nums[i]; j--) {
dp[j] += dp[j -nums[i]];
}
}
return dp[bagSize];
}
}
總結:一維陣列的形式初始化只需要dp[0] = 1就行了,想象下nums[0]為0時,j = 0時遞推公式dp[j] += dp[j -nums[i]];依舊可以用,此時相當於dp[0]+dp[0] = 2了。
474.一和零
題目連結:474.一和零
文件講解︰程式碼隨想錄(programmercarl.com)
影片講解︰一和零
日期:2024-10-10
Java程式碼如下:
class Solution {
public int findMaxForm(String[] strs, int m, int n) {
int[][] dp = new int[m + 1][n + 1];
int oneNum, zeroNum;
for (String str : strs) {
oneNum = 0;
zeroNum = 0;
for (char ch : str.toCharArray()) {
if (ch == '0') {
zeroNum++;
} else {
oneNum++;
}
}
for (int i = m; i >= zeroNum; i--) {
for (int j = n; j >= oneNum; j--) {
dp[i][j] = Math.max(dp[i][j], dp[i - zeroNum][j - oneNum] + 1);
}
}
}
return dp[m][n];
}
}