本文目录
leetcode 21天动态规划入门——从0到0.5【Day07】请叫我股神!
写在前面
圣诞节后的第一天,来到了动态规划的鼻祖题,买卖股票的冷冻期~要想成股神,dp少不了,那就让我们今天来炒炒股!冲啊!
题目
题目一
- 最佳观光组合
给你一个正整数数组 values,其中 values[i] 表示第 i 个观光景点的评分,
并且两个景点 i 和 j 之间的 距离 为 j - i。
一对景点(i < j)
组成的观光组合的得分为 values[i] + values[j] + i - j ,
也就是景点的评分之和 减去 它们两者之间的距离。
返回一对观光景点能取得的最高分。
示例1:
输入:values = [8,1,5,2,6]
输出:11
解释:i = 0, j = 2,
values[i] + values[j] + i - j = 8 + 5 + 0 - 2 = 11
示例2:
输入:values = [1,2]
输出:2
提示
2 <= values.length <= 5 * 10^4
1 <= values[i] <= 1000
思路
经典的动态规划题:
主要麻烦的就是要考虑其滚动数组记录的最大值。
观察示例 :
维护一个dp数组用来记录到达从0到i的最大经典得分的值
再来一个变量max,滚动记录最大值
故此能得到状态转化方程:
dp[i] = Math.max(dp[i-1],i+values[i])
滚动数组中的变量:
max = Math.max(max,dp[i-1] + values[i] - i)
代码实现
class Solution {
public int maxScoreSightseeingPair(int[] values) {
int dp[] = new int [values.length+1];
//当只有一个景点时,其最大的景点得分就是values[0] + 0 - 0;
dp[0] = values[0] + 0;
int max = 0;
for (int j = 1 ;j<values.length;j++){
//用来记录当前的最大得分
max = Math.max(max,dp[j-1]+values[j]-j);
// 动态转化方程
dp[j] = Math.max(dp[j-1],values[j]+j);
}
return max;
}
}
执行结果

代码优化
至少思路简单但是肯定能优化 按照昨天学的知识 将一个变量来代替我们维护的数组。
class Solution {
public int maxScoreSightseeingPair(int[] values) {
//利用score来代替我们的dp数组用到了贪心算法
int max = 0 ,score = values[0] + 0;
for (int j = 1 ;j <values.length;j++ ){
max = Math.max(max,score + values[j] - j);
score = Math.max(score,values[j] + j);
}
return max;
}
}

题目二
- 买卖股票的最佳时机
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子
卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。
如果你不能获取任何利润,返回 0 。
示例
示例1:
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入
,在第 5 天(股票价格 = 6)的时候卖出,
最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6,
因为卖出价格需要大于买入价格;
同时,你不能在买入前卖出股票。
示例2:
输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。
提示
1 <= prices.length <= 10^5
0 <= prices[i] <= 10^4
思路
这道题相比于之前的题需要进行分类判断。
当你持有股票的时候与当你没持有股票的时候两种情况
- 当你今天未持有股票时,①前一天也没有持有股票的时候。②你可以通过卖出当天股票来获利prices[i] 取最大值。
- 当你今天持有股票时的情况①是昨天本来就持有股票②或者今天买入股票花费prices[i]的钱取得最大值。
- dp[i][0] 表示第i天持有股票所得现金。
- dp[i][1] 表示第i天不持有股票所得最多现金
代码实现
class Solution {
public int maxProfit(int[] prices) {
int dp[][] = new int [prices.length][2];
//当第一天未持有股票时的现金
dp[0][0] = 0;
//第一天持有股票时候需要花费prices[0]来购买当天的股票
dp[0][1] = -prices[0];
for (int i = 1;i< prices.length;i++){
//动态转化方程 当持有股票时 最大获利 当天未持有股票的最大收益
dp[i][0] = Math.max(dp[i-1][0],prices[i]+dp[i-1][1]);
dp[i][1] = Math.max(dp[i-1][1],-prices[i]);
}
//返回的是到达最后一天没有持有股票时候 会有 最大获利
return dp[prices.length-1][0];
}
}
执行结果

题目三
- 买卖股票的最佳时机 II
给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。
你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例
示例1:
输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,
在第 3 天(股票价格 = 5)的时候卖出,
这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,
在第 5 天(股票价格 = 6)的时候卖出,
这笔交易所能获得利润 = 6-3 = 3 。
示例2:
输入: prices = [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,
在第 5 天 (股票价格 = 5)的时候卖出,
这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,
之后再将它们卖出。
因为这样属于同时参与了多笔交易,
你必须在再次购买前出售掉之前的股票。
提示
1 <= prices.length <= 3 * 10^4
0 <= prices[i] <= 10^4
思路
这道题和上一道题思路相通,唯一区别就是可以买卖多次。
这重申一下dp数组的含义:
- dp[i][0] 表示第i天持有股票所得现金。
- dp[i][1] 表示第i天不持有股票所得最多现金
代码实现
class Solution {
public int maxProfit(int[] prices) {
int dp[][] = new int [prices.length][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i< prices.length;i++){
dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1] + prices[i]);
dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] - prices[i]);
}
return dp[prices.length-1][0];
}
}
执行结果

代码优化
不过这题说实在的是个脑筋急转弯
只要后一天别前一天的值大就加上该数值。
class Solution {
public int maxProfit(int[] prices) {
int ans=0;
for(int i=1;i<=prices.length-1;i++)
{
if(prices[i]>prices[i-1])
{
ans+=prices[i]-prices[i-1];
}
}
return ans;
}
}
优化结果

写在后面
今天写完收工了哦~
动态规划已经练习到了第七天了!
不知不觉就到一个星期了
什么也不说了 坚持打卡每一天!
加油~热爱算法以及编程的你!
最后
每天进步点 每天收获点
愿诸君 事业有成 学有所获
如果觉得不错 别忘啦一键三连哦~

被折叠的 条评论
为什么被折叠?



