Leetcode上的DP问题太多了,先把一部分比较需要思考的记录下来,之后再进行总结。
638. 大礼包
在LeetCode商店中, 有许多在售的物品。然而,也有一些大礼包,每个大礼包以优惠的价格捆绑销售一组物品。现给定每个物品的价格,每个大礼包包含物品的清单,以及待购物品清单。请输出确切完成待购清单的最低花费。每个大礼包的由一个数组中的一组数据描述,最后一个数字代表大礼包的价格,其他数字分别表示内含的其他种类物品的数量。任意大礼包可无限次购买。
示例 1:
输入: [2,5], [[3,0,5],[1,2,10]], [3,2]
输出: 14
解释: 有A和B两种物品,价格分别为¥2和¥5。 大礼包1,你可以以¥5的价格购买3A和0B。 大礼包2, 你可以以¥10的价格购买1A和2B。 你需要购买3个A和2个B, 所以你付了¥10购买了1A和2B(大礼包2),以及¥4购买2A。
740. 删除与获得点数
给定一个整数数组 nums
,你可以对它进行一些操作。
每次操作中,选择任意一个 nums[i]
,删除它并获得 nums[i]
的点数。之后,你必须删除每个等于 nums[i] - 1
或 nums[i] + 1
的元素。
开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。
这个题目在学校的算法实验4上出现过。对于每一个数字,如果选择删除它,那么就必须删除和它相邻的所有元素。这与打家劫舍那道题很相似,只是这个题最好先把各数字及出现的次数存入哈希表中。原题已经给定了数字的范围。
class Solution {
public:
int deleteAndEarn(vector<int>& nums) {
if(nums.size() == 0)
return 0;
vector<int> dp(10000 + 1, 0);
vector<int> table(10000 + 1, 0);
for(auto i : nums)
table[i]++;
dp[1] = max(dp[0], table[1]);
for(int i = 2; i <= 10000; i++)
{
dp[i] = max(dp[i - 1], i * table[i] + dp[i - 2]);
}
return dp[10000];
}
};
646. 最长数对链
给出 n
个数对。 在每一个数对中,第一个数字总是比第二个数字小。
现在,我们定义一种跟随关系,当且仅当 b < c
时,数对(c, d)
才可以跟在 (a, b)
后面。我们用这种形式来构造一个数对链。给定一个对数集合,找出能够形成的最长数对链的长度。你不需要用到所有的数对,你可以以任何顺序选择其中的一些数对来构造。
由于这题在动态规划的标签下,先考虑的是DP的做法。由于输入不一定是有序的,所以要先对输入进行排序。对于数对(a, b)和(c, d),排序规则为b < d。然后定义状态dp[i]表示以第i个数对结尾所形成的数对链的长度,有dp[i] = max(dp[i], 1 + dp[j[)。其实这个做法与LIS的做法非常相似。
在网上查阅题解发现还可以用贪心来解。其实这个问题就是活动选择问题,可以套用它的解法。
class Solution {
public:
static bool cmp(const vector<int>& p1, const vector<int>& p2)
{
return p1[1] < p2[1];
}
int findLongestChain(vector<vector<int>>& pairs)
{
if(pairs.size() < 2)
return pairs.size();
sort(pairs.begin(), pairs.end(), cmp);
vector<int> dp(pairs.size(), 0);
dp[0] = 1;
for(int i = 1; i < pairs.size(); i++)
{
int temp = 0;
for(int j = 0; j < i; j++)
if(pairs[j][1] < pairs[i][0])
temp = max(temp, dp[j]);
//dp[i] = 1 + temp;
dp[i] = max(dp[i - 1], 1 + temp);
}
/*int res = INT_MIN;
for(int i = 0; i < pairs.size(); i++)
res = max(res, dp[i]);
return res;*/
return dp[pairs.size() - 1];
}
};