赞
踩
给定一个数组 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。
因为股票就买卖一次,那么贪心的想法很自然就是取最左最小值,取最右最大值,那么得到的差值就是最大利润。
还是比较基于贪心算法的方法
- int maxProfit(int* prices, int pricesSize) {
- int dp[pricesSize];//在第j天 及以前,能得到的最大收益
- memset(dp, 0, sizeof(dp));
- if(pricesSize==0 || pricesSize==1) return 0;
-
- dp[0]=0;
- dp[1]=fmax(0,prices[1]-prices[0]);
- int min=fmin(prices[0],prices[1]);//记录最小的成本
-
- for (int j=2;j<pricesSize;j++){
- if(min>prices[j]) {//应该在第j天卖出
- min=prices[j];
- dp[j]=dp[j-1];//成本价改变,但是在第j天卖出 最大收益没办法计算到第j-1天
- }
- else dp[j]=fmax(dp[j-1],prices[j]-min);
- }
-
- for (int j=0;j<pricesSize;j++){
- printf("%d",dp[j]);
- }
-
- return dp[pricesSize-1];
- }
确定dp数组(dp table)以及下标的含义
dp[i][0] 表示第i天持有股票所得最多现金,其实一开始现金是0,那么加入第i天买入股票现金就是 -prices[i], 这是一个负数。
dp[i][1] 表示第i天不持有股票所得最多现金
注意这里说的是“持有”,“持有”不代表就是当天“买入”!也有可能是昨天就买入了,今天保持持有的状态
确定递推公式
如果第i天持有股票即dp[i][0], 那么可以由两个状态推出来
那么dp[i][0]应该选所得现金最大的,所以dp[i][0] = max(dp[i - 1][0], -prices[i]);
如果第i天不持有股票即dp[i][1], 也可以由两个状态推出来
同样dp[i][1]取最大的,dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);
这样递推公式我们就分析完了
dp数组如何初始化
由递推公式 dp[i][0] = max(dp[i - 1][0], -prices[i]); 和 dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]);可以看出
其基础都是要从dp[0][0]和dp[0][1]推导出来。
那么dp[0][0]表示第0天持有股票,此时的持有股票就一定是买入股票了,因为不可能有前一天推出来,所以dp[0][0] -= prices[0];
dp[0][1]表示第0天不持有股票,不持有股票那么现金就是0,所以dp[0][1] = 0;
确定遍历顺序
从递推公式可以看出dp[i]都是由dp[i - 1]推导出来的,那么一定是从前向后遍历。
- int maxProfit(int* prices, int pricesSize) {
- int dp[pricesSize][2];//第几天,0表示第j天不持有股票(包括j天卖掉),1表示持有股票(包括j天买入)
- memset(dp, 0, sizeof(dp));
- dp[0][0]=0;
- dp[0][1]=-prices[0];
-
- for (int j=1;j<pricesSize;j++){
- dp[j][0]=fmax(dp[j-1][0],prices[j] + dp[j-1][1]);
- dp[j][1]=fmax(dp[j-1][1],-prices[j]);
- }
- return fmax(dp[pricesSize-1][0],dp[pricesSize-1][1]);
- }
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
- int maxProfit(int* prices, int pricesSize) {
- int dp[pricesSize][2];
- //0表示这天手上没有股票,包括这天卖出,最多手上有多少钱
- //1表示这天手上有股票,包括这天买到,最多手上有多少钱
- memset(dp, 0, sizeof(dp));
- dp[0][0]=0;
- dp[0][1]=-prices[0];
-
- for(int j=1;j<pricesSize;j++){
- //第j天最后手上没有股票的两种情况:本来就没有,卖掉了
- dp[j][0]= fmax(dp[j-1][0], prices[j] + dp[j-1][1]);
- //第j天手上最后有股票的两种情况:本来就有,今天刚买了股票(买股票要求本来手上没有股票)
- dp[j][1]= fmax(dp[j-1][1], dp[j-1][0]-prices[j]);
- }
- return fmax(dp[pricesSize-1][0], dp[pricesSize-1][1]);
- }
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入:prices = [3,3,5,0,0,3,1,4]
输出:6 解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3。
按照题意,区分每一天的状态!
然后会发现无操作的状态可以不用考虑
重点是初始化!!!为什么day0 第三个状态需要初始化呢?:dp【i】【j】记录的是在第i天 j种情况中花费掉的钱,需要算在里面,后续计算的dp【i】【3】会用到
为什么最后一个的k情况是最大的:现在最大的时候一定是卖出的状态,而两次卖出的状态现金最大一定是最后一次卖出。如果想不明白的录友也可以这么理解:如果第一次卖出已经是最大值了,那么我们可以在当天立刻买入再立刻卖出。所以dp[4][4]已经包含了dp[4][2]的情况。也就是说第二次卖出手里所剩的钱一定是最多的。
最后一单未进行的情况,或者说可以理解成原地出售的情况,其实暗含在dp[i][4]=fmax(dp[i-1][4]中了
- int maxProfit(int* prices, int pricesSize) {
- int dp[pricesSize][5];//没有操作 0 ,能拿到的最大的钱
- //第一次持有股票 1
- //第一次不持有股票 2
- //第二次持有股票 3
- //第二次不持有股票 4
- memset(dp,0,sizeof(dp));
- dp[0][1]=-prices[0];
- dp[0][3]=-prices[0];//这个初始化很重要!!!
-
-
- for (int i=1;i<pricesSize;i++){
- //dp[i][0]=dp[i-1]
- dp[i][1]=fmax(dp[i-1][1],-prices[i]);//分为本来就有股票,和今天买入的股票
- dp[i][2]=fmax(dp[i-1][2],prices[i] + dp[i-1][1]);
- dp[i][3]=fmax(dp[i-1][3], dp[i-1][2]-prices[i]);
- dp[i][4]=fmax(dp[i-1][4],prices[i]+dp[i-1][3]);
-
- }
- return dp[pricesSize-1][4];
-
- }
给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入:k = 2, prices = [2,4,1]
输出:2 解释:在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2。
示例 2:
输入:k = 2, prices = [3,2,6,5,0,3]
输出:7 解释:在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
- int maxProfit(int k, int* prices, int pricesSize) {
- int total=2*k;
- int dp[pricesSize][total];
- //1,3,5,7,9...这些是卖出的
- //0是第一次有股票,1对应第一次卖掉
- memset(dp,0,sizeof(dp));
-
- for (int i=0;i<k;i++){
- dp[0][2*i]=-prices[0];
- }
-
-
- for (int t=1;t<pricesSize;t++){
- dp[t][0]=fmax(dp[t-1][0],-prices[t]);///一开始这个赋值没有想清楚
- dp[t][1]=fmax(dp[t-1][1] , prices[t]+dp[t-1][0]);
-
- for (int i=1;i<k;i++){
-
- //第i次买到股票,本来手上就有 && 今天刚买
- dp[t][2*i]= fmax(dp[t-1][2*i], dp[t-1][2*i-1]-prices[t] );
- //第i次卖掉股票,本来就没有or卖掉了
- dp[t][2*i+1]=fmax(dp[t-1][2*i+1] , prices[t]+dp[t-1][2*i]);
-
-
- }
- }
-
- return dp[pricesSize-1][2*k-1];
- }
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
示例:
具体可以区分出如下四个状态:——状态要尽量分的细致一点!!!只考虑昨天 对 今天的影响
- int maxProfit(int* prices, int pricesSize) {
- //0:手上有股票——手上有最多的钱是多少?
- //1:手上没有股票,且不是今天卖出的股票
- //2:今天卖出的股票
- //3:在冷冻期
-
- int dp[pricesSize+1][4];
- memset(dp,0,sizeof(dp));
-
- dp[0][0]=-prices[0];
-
- for(int j=1;j<pricesSize;j++){
- dp[j][0]=fmax(dp[j-1][0], fmax(dp[j-1][1]-prices[j] , dp[j-1][3] -prices[j] ) );
- dp[j][1]= fmax(dp[j-1][1], fmax(dp[j-1][2],dp[j-1][3]) );
- dp[j][2]= dp[j-1][0] +prices[j];
- dp[j][3] = dp[j-1][2];
-
- }
-
-
-
-
- return fmax(dp[pricesSize-1][1],fmax(dp[pricesSize-1][2],dp[pricesSize-1][3]));
- }
给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
示例 1:
只要在122的基础上,加上卖股票的时候扣去手续费即可!
- int maxProfit(int* prices, int pricesSize, int fee) {
- int dp[pricesSize][2];
- //0表示这天手上没有股票,包括这天卖出,最多手上有多少钱
- //1表示这天手上有股票,包括这天买到,最多手上有多少钱
- memset(dp, 0, sizeof(dp));
- dp[0][0]=0;
- dp[0][1]=-prices[0];
-
- for(int j=1;j<pricesSize;j++){
- //第j天最后手上没有股票的两种情况:本来就没有,卖掉了
- dp[j][0]= fmax(dp[j-1][0], prices[j] + dp[j-1][1]-fee);//就是这里!!!!!!!!!!!!!!!!!
- //第j天手上最后有股票的两种情况:本来就有,今天刚买了股票(买股票要求本来手上没有股票)
- dp[j][1]= fmax(dp[j-1][1], dp[j-1][0]-prices[j]);
- }
- return fmax(dp[pricesSize-1][0], dp[pricesSize-1][1]);
-
- }
之前我们已经把力扣上股票系列的题目都讲过的,但没有来一篇股票总结,来帮大家高屋建瓴,所以总结篇这就来了!
贪心思路:
最左最小值,最右最大值
复杂一些之后需要使用动态规划的思路:
将每天股票状态分成若类,每一类都可以用前一天的状态决定
讨论每天每种状态的最大值
注意递推公式细节和初始化
有时候会写错dp和nums数组,还有要确保下标有效
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。