隨想錄 Day45 1049. 最后一塊石頭的重量 II 494. 目標和 474.一和零
1049. 最后一塊石頭的重量 II
題目鏈接
有一堆石頭,用整數數組 stones 表示。其中 stones[i] 表示第 i 塊石頭的重量。
每一回合,從中選出任意兩塊石頭,然后將它們一起粉碎。假設石頭的重量分別為 x 和 y,且 x <= y。那么粉碎的可能結果如下:
如果 x == y,那么兩塊石頭都會被完全粉碎;
如果 x != y,那么重量為 x 的石頭將會完全粉碎,而重量為 y 的石頭新重量為 y-x。
最后,最多只會剩下一塊 石頭。返回此石頭 最小的可能重量 。如果沒有石頭剩下,就返回 0。
第一次提交
轉化為已經熟悉的背包問題
class Solution {
public:int lastStoneWeightII(vector<int>& stones) {int all = accumulate(stones.begin(), stones.end(), 0);int half = all / 2;vector<int> dp(half + 1, 0);for (int i = 0; i < stones.size(); i++) {for (int j = half; j >= 0; j --) {if (stones[i] <= j) {dp[j] = max(dp[j], dp[j - stones[i]] + stones[i]);}}}return all - 2* dp[half];}
};
學習題解
隨想錄 思路相似
494. 目標和
題目鏈接 494 給你一個非負整數數組 nums 和一個整數 target 。
向數組中的每個整數前添加 ‘+’ 或 ‘-’ ,然后串聯起所有整數,可以構造一個 表達式 :
例如,nums = [2, 1] ,可以在 2 之前添加 ‘+’ ,在 1 之前添加 ‘-’ ,然后串聯起來得到表達式 “+2-1” 。
返回可以通過上述方法構造的、運算結果等于 target 的不同 表達式 的數目。
提示:
1 <= nums.length <= 20
0 <= nums[i] <= 1000
0 <= sum(nums[i]) <= 1000
-1000 <= target <= 1000
第一次提交
直覺直接上回溯+記憶化搜索
class Solution {
public:int res;int his[21][40001];int backtrack(vector<int>& nums, int cur, int target) {//cout << cur <<" cur " <<target<< " target "<<endl;if (target == 0 && cur == nums.size()) {his[cur][target + 20000] = 1;return 1;}if (cur == nums.size()) {return 0;}if (his[cur][target + 20000] == 0) {his[cur][target + 20000] = backtrack(nums, cur+1, target + nums[cur]) + backtrack(nums, cur+1, target - nums[cur]);}return his[cur][target + 20000];}int findTargetSumWays(vector<int>& nums, int target) {res = 0;memset(his, 0, sizeof(his));return backtrack(nums, 0, target); }
};
學習題解,轉化為背包問題
如何轉化為01背包問題呢。
假設加法的總和為x,那么減法對應的總和就是sum - x。
所以我們要求的是 x - (sum - x) = target
x = (target + sum) / 2
此時問題就轉化為,裝滿容量為x的背包,有幾種方法。
這里的x,就是bagSize,也就是我們后面要求的背包容量。
class Solution {
public:int findTargetSumWays(vector<int>& nums, int target) {int total = accumulate(nums.begin(), nums.end(), 0);if (abs(target) > total) return false;if ((target + total) % 2 == 1) return 0;int bagSize = (target + total) / 2;int dp[bagSize + 1];memset(dp, 0, sizeof(dp));dp[0] = 1;for(int i = 0; i < nums.size(); i++) {for (int j = bagSize; j >= 0; j--) {if (nums[i] <= j) {dp[j] = dp[j] + dp[j - nums[i]];}}}return dp[bagSize];}
};
474.一和零
題目鏈接 474 給你一個二進制字符串數組 strs 和兩個整數 m 和 n 。
請你找出并返回 strs 的最大子集的長度,該子集中 最多 有 m 個 0 和 n 個 1 。
如果 x 的所有元素也是 y 的元素,集合 x 是集合 y 的 子集 。
第一次提交
延用背包問題解決思路
class Solution {
public:vector<int> transform(string str) {vector<int> res(2, 0);for(char c: str) {if (c == '0') res[0]++;if (c == '1') res[1]++;}return res;}int findMaxForm(vector<string>& strs, int m, int n) {int dp[m+1][n+1];memset(dp, 0, sizeof(dp));vector<vector<int>> cnt;for(int i = 0; i < strs.size(); i++) {cnt.push_back(transform(strs[i]));}for (int i = 0; i < cnt.size(); i++) {for ( int j = m; j >= 0; j--) {for(int k = n; k >= 0; k--) {if (cnt[i][0] <= j && cnt[i][1] <= k) {dp[j][k] = max(dp[j][k], dp[j -cnt[i][0]][k - cnt[i][1]] + 1);}}}}return dp[m][n];}
};
學習題解
隨想錄 思路上沒區別