一招团灭6道股票问题

所谓一招: 其实就是穷举法 ,优化都是后边得到的
具体看下方链接

力扣大神的超详细解说

1. 买卖股票的最佳时机 买一次

class Solution {
public:
    int maxProfit(vector<int>& prices) {    
        if(prices.size() ==0 )  return 0;
    
    //获取最低成本
    int buy  = 0;
    int tmpEarn= 0;//暂时利润
    int maxEarn =0;//最大利润

    for(int i=0; i < prices.size(); ++i )
    {
        if(prices[i] < prices[buy]) //降价中
            buy = i; //换今天买入
        
        //否则 (+不加else都行,)
        tmpEarn = prices[i] - prices[buy];//计算当前利润
        //判断是否大于之前的利润,大于就更新
        maxEarn = maxEarn  > tmpEarn ? maxEarn : tmpEarn;
    }
        return maxEarn;  
    }
   };

**//方法二: 推荐 **

class Solution {
public:
    int maxProfit(vector<int>& prices) {
	//方法二
	int  n= prices.size();
	if (n<2) return 0;
	
	vector<vector<int>> dp(n ,vector<int>(2));
	for (int i = 0; i < n; i++)
	 {
	    if (i - 1 == -1) 
	    {
	        dp[i][0] = 0;
	        dp[i][1] = -prices[i];//买的时候投入prices[i]
	        continue;
	    }
	    dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i]);
	    dp[i][1] = max(dp[i-1][1], -prices[i]);//因为只买一次,买就是投资,投资利润就是负的
	}
	    return dp[n - 1][0];
}
};

二:可以无数次买卖

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if(prices.size() ==0 )  return 0;
    
        int ret =0;//总利润
        for(int i=0; i < prices.size() - 1; ++i)
        {
            int tmp = prices[i+1] - prices[i];
            if(tmp > 0)//明天有利润,那就赚了他
                ret += tmp;
        }
        return ret;
    }
};

方法二 推荐

class Solution {
public:
    int maxProfit(vector<int>& prices) {
//方法二: 递推:  今天的只需考虑昨天的情况, 因此 一个变量即可
        int dp_i_0 =0;  
        int dp_i_1 = -prices[0];
        for(int i=0; i<prices.size(); ++i)
        {
            //注意暂存一下昨天数据,方便迭代递推
            int temp = dp_i_0;
            dp_i_0 = max(dp_i_0, dp_i_1 + prices[i]);
            dp_i_1 = max(dp_i_1, temp - prices[i]);
        }
        return dp_i_0;
    }
};

三: 无数次买+冷却1天:

每次 sell 之后要等一天才能继续交易。只要把这个特点融入上一题的状态转移方程即可:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-2][0] - prices[i])
解释:第 i 天选择 buy 的时候,要从 i-2 的状态转移,而不是 i-1 。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if(n < 2) return 0;

        int dp_i_0 = 0;
        int dp_i_1 = -prices[0];
        int dp_pre_0 = 0;//1天冷冻期。
        for(int i=0; i< n; ++i)
        {
            int temp =dp_i_0; //暂存今天,作为明天的前一天
            dp_i_0 =max(dp_i_0, dp_i_1 + prices[i]);
            //解释: 今天有 1 :昨天有:而昨天没-->昨天卖掉了,那么去前天没有的时候进行计算
            dp_i_1 =max(dp_i_1, dp_pre_0 - prices[i]);
            dp_pre_0 = temp;
        }
        return dp_i_0;
    }
};

四 最多只能买 2次

还记得前面总结的「穷举框架」吗?就是说我们必须穷举所有状态。其实我们之前的解法,都在穷举所有状态,只是之前的题目中 k 都被化简掉了。这道题由于没有消掉 k 的影响,所以必须要对 k 进行穷举:

dp[i][2][0] = max(dp[i-1][2][0], dp[i-1][2][1] + prices[i])
dp[i][2][1] = max(dp[i-1][2][1], dp[i-1][1][0] - prices[i])
dp[i][1][0] = max(dp[i-1][1][0], dp[i-1][1][1] + prices[i])
dp[i][1][1] = max(dp[i-1][1][1], -prices[i])
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n < 2) return 0;
        
        //  只有两次,我们可以穷就下所有有的
        //中间的1 / 2 表示 有几次选择机会
        //后边的1 /0  拥有 还是未拥有
        int dp_1_0 =0; int dp_1_1 = -prices[0];
        int dp_2_0 =0; int dp_2_1 = -prices[0];  
        
        for(int i =0; i<n; ++i)//逆向思维剩几次机会
        {
            dp_2_0 = max(dp_2_0, dp_2_1 + prices[i]);
            dp_2_1 = max(dp_2_1, dp_1_0 - prices[i]);//买了一只
            dp_1_0 = max(dp_1_0, dp_1_1 + prices[i]);
            dp_1_1 = max(dp_1_1, -prices[i]);//注意这里dp_1_0已经变了
        }
        return dp_2_0;
    }
};

五 交易次数为K次

有了上一题 k = 2 的铺垫,这题应该和上一题的第一个解法没啥区别。但是出现了一个超内存的错误,原来是传入的 k 值会非常大,dp 数组太大了。现在想想,交易次数 k 最多有多大呢?

一次交易由买入和卖出构成,至少需要两天。所以说有效的限制 k 应该不超过 n/2,如果超过,就没有约束作用了,相当于 k = +infinity。这种情况是之前解决过的。

直接把之前的代码重用:

int maxProfit_k_any(int max_k, int[] prices) {
    int n = prices.length;
    if (max_k > n / 2) //次数不限制
        return maxProfit_k_inf(prices);

    int[][][] dp = new int[n][max_k + 1][2];
    for (int i = 0; i < n; i++) 
        for (int k = max_k; k >= 1; k--) {
            if (i - 1 == -1) { /* 处理 base case */ }
            dp[i][k][0] = max(dp[i-1][k][0], dp[i-1][k][1] + prices[i]);
            dp[i][k][1] = max(dp[i-1][k][1], dp[i-1][k-1][0] - prices[i]);     
        }
    return dp[n - 1][max_k][0];
}

六 交易需要手续费

状态方程

dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i] - fee)
解释:相当于买入股票的价格升高了。
在第一个式子里减也是一样的,相当于卖出股票的价格减小了。

int n = prices.size();
    if(n < 2) return 0;

    int dp_i_0 = 0, dp_i_1 = INT_MIN;//注意这个参数。 INT最小值
    for (int i = 0; i < n; i++) {
        int temp = dp_i_0;
        dp_i_0 = max(dp_i_0, dp_i_1 + prices[i]);
        dp_i_1 = max(dp_i_1, temp - prices[i] - fee);
    }
    return dp_i_0;
   }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值