动态规划算法7
LeetCode 198 打家劫舍 2023.12.12
int rob(vector<int>& nums) {
//1确定dp数组及其下标含义,dp[i]表示遍历(0,i)nums子数组的最大金额
vector<int> dp(nums.size());
//3初始化,dp[0]=第一间房屋的金额;dp[1]=第一间与第二间的最大金额
dp[0] = nums[0];
//需要判断nums数组大小,当size>1时才能初始化dp[1]
if(nums.size() >= 2)
dp[1] = max(nums[0], nums[1]);
//2确定递推公式,dp[i]=max(取当前房屋i金额+第i-2房间前的最大金额,第i-1间房间前的最大金额)
for (int i = 2; i < nums.size(); i++)
{
dp[i] = max(nums[i]+dp[i-2], dp[i-1]);
}
return dp[nums.size()-1];
}
LeetCode 213 打家劫舍-ii 2023.12.12
class Solution {
public:
//求某一非循环数组的最大打家劫舍价值
int robrange(vector<int>& nums, int begin, int end)
{
//1确定dp数组及其下标含义,dp[i]表示遍历(begin,i)nums子数组的最大金额
vector<int> dp(nums.size(), 0);
//3初始化,dp[begin]=第begin间房屋的金额;dp[begin+1]=相邻这两间的最大金额
dp[begin] = nums[begin];
dp[begin+1] = max(nums[begin], nums[begin+1]);
//2确定递推公式,dp[i]=max(取当前房屋i金额+第i-2房间前的最大金额,第i-1间房间前的最大金额)
for(int i = begin+2; i <= end; i++)
dp[i] = max(nums[i] + dp[i-2], dp[i-1]);
return dp[end];
}
int rob(vector<int>& nums) {
//分类讨论
//1、只有一间房屋,那么返回该间房的金额
if(nums.size() == 1)
return nums[0];
//2、有两间房屋,那么返回这两间房的较大金额
if(nums.size() == 2)
return max(nums[0], nums[1]);
//3、有多间房,那么选择动态规划的最大值
//环形数组的最后解范围有三中,1、[0, nums.size()-2];2、[1, nums.size()-1];3、[1, nums.size()-2]
//第二种情况包括第三种情况,那么选取第一、二种情况的较大值作为答案
else
return max(robrange(nums, 0, nums.size()-2), robrange(nums, 1, nums.size()-1));
}
};
LeetCode 337 打家劫舍-iii 2023.12.12
class Solution {
public:
//暴力求解,需配合查找表使用,否则超时
//unordered_map<TreeNode*, int> unmap;
// int rob(TreeNode* root) {
// if(root == NULL)
// return 0;
// if(root->left == NULL && root->right == NULL)
// return root->val;
// if(unmap[root])
// return unmap[root];
// //1取当前root,那么值为当前root值+其4个孙子的值
// int val1 = root->val;
// if(root->left)
// val1 += rob(root->left->left) + rob(root->left->right);
// if(root->right)
// val1 += rob(root->right->left) + rob(root->right->right);
// //2不取当前root,那么值为其2个儿子的值的和
// int val2 = rob(root->left) + rob(root->right);
// //将当前root的最大价值存入查找表,用于下次计算时查找,提高效率
// unmap[root] = max(val1, val2);
// //返回当前root的最大价值
// return unmap[root];
// }
//递归+动态规划方法
vector<int> robTree(TreeNode* root)
{
//递归退出条件
if(root == NULL)
return {
0, 0};
//创建要返回的当前数组,cur[0]表示不取当前root值时的价值;cur[1]表示取当前root值时的价值
vector<int> cur(2, 0);
vector<int> left = robTree(root->left);
vector<int> right = robTree(root->right);
//不取当前root值
cur[0] = max(left[0], left[1]) + max(right[0], right[1]);
//取当前root值
cur[1] = root->val + left[0] + right[0];
return cur;
}
int rob(TreeNode* root) {
vector<int> result = robTree(root);
return max(result[0], result[1]);
}
};
LeetCode 121 买卖股票的最佳时机 2023.12.12
int maxProfit(vector<int>& prices) {
//暴力求解
// int result = 0;
//两次循环求数组中最大元素差
// for (int i = 0; i < prices.size(); i++)
// {
// for(int j = i; j < prices.size(); j++)
// result = max(result, prices[j]-prices[i]);
// }
// return result;
//贪心算法
//更新最小值与最大收益
// int minValue = prices[0];
// int result = 0;
// for (int i = 0; i < prices.size(); i++)
// {
// minValue = min(minValue, prices[i]);
// result = max(result, prices[i]-minValue);
// }
// return result;
//动态规划
//更新最小值与最大收益
// vector<int> dp(prices.size(), 0);
// int min = prices[0];
// for(int i = 1; i < prices.size(); i++)
// {
// if(min > prices[i])
// min = prices[i];
// dp[i] = max(prices[i]- min, dp[i-1]);
// }
// return dp[prices.size()-1];
//1创建dp二维数组
//dp[i][0]表示遍历到第i天时持有股票的当前收入;dp[i][1]表示遍历到第i天时未持有股票的当前收入
vector<vector<int>> dp(prices.size(), vector<int>(2,0));
//3初始化,第一天持有股票的收入为-prices[0],其他值为0
dp[0][0] = -prices[0];
//2确定递推公式,4确定遍历顺序
for (int i = 1; i < prices.size(); i++)
{
//第i天持有股票的收入=max(股票不卖(上一天持有股票的收入),之前买的不算,买当天的股票的收入)
dp[i][0] = max(dp[i-1][0], -prices[i]);
//第i天未持有股票的收入=max(上一天未持有股票的收入,今天卖股票的收入)
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]);
}
return dp[prices.size()-1][1];
}
LeetCode 122 买卖股票的最佳时机-ii 2023.12.12
int maxProfit(vector<int>& prices) {
//贪心算法
// //result存储收益
// int result = 0;
// //cur存储当前手中股票价格,因为股票价格有0,所以初始化手中没股票时cur=-1
// int cur = -1;
// //遍历
// for (int i = 0; i < prices.size(); i++)
// {
// //当手中没股票且当日价格小于下一日价格时买入并遍历到下一天
// if(cur == -1 && i+1 < prices.size() && prices[i] < prices[i+1])
// {
// cur = prices[i];
// continue;
// }
// //当手中有股票,且当日股价大于买入价,而且明天就没有价格了或者明天价格比今天低的时候卖出,更新收益
// if(cur != -1 && prices[i] > cur && (i == prices.size()-1 || (i+1 < prices.size() && prices[i] > prices[i+1])))
// {
// result += (prices[i] - cur);
// cur = -1;
// }
// }
// return result;
//动态规划算法
//1确定dp二维数组
//dp[i][0]表示遍历到第i天时持有股票的当前收入;dp[i][1]表示遍历到第i天时未持有股票的当前收入
vector<vector<int>> dp(prices.size(), vector<int>(2, 0));
//3初始化,第一天持有股票的收入为-prices[0],其他值为0
dp[0][0] = -prices[0];
//2确定递推公式,4确定遍历顺序
for (int i = 1; i < prices.size(); i++)
{
//第i天持有股票的收入=max(股票不卖(上一天持有股票的收入),昨天没持有买完今天的股票的收入)
dp[i][0] = max(dp[i-1][0], dp[i-1][1]-prices[i]);
//第i天未持有股票的收入=max(上一天未持有股票的收入,今天卖股票的收入)
dp[i][1] = max(dp[i-1][1], dp[i-1][0]+prices[i]);
}
return dp[prices.size()-1][1];
}