股票问题是我们常见的算法问题,因为它可以考察我们对算法的理解以及我们的编程思维方式,同时它也是贪心算法跟动态规划的高度体现!下面是LeetCode上面所有的股票问题!
`下面两个核心方程!
第i天不持有 由 第i-1天不持有然后不操作 和 第i-1天持有然后卖出 两种情况的最大值转移过来
dp[i][k][0] = Math.max(dp[i - 1][k][0], dp[i - 1][k][1] + prices[i])
第i天持有 由 第i-1天持有然后不操作 和 第i-1天不持有然后买入 两种情况的最大值转移过来
dp[i][k][1] = Math.max(dp[i - 1][k][1], dp[i - 1][k - 1][0] - prices[i])
i代表天,k代表交易次数,0代表不持有也就是sell,1代表持有也就是buy!
`
给定一个数组 prices ,它的第i个元素prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
121题限制条件:一次交易机会
那么我们目的是求出合适的买入和卖出机会,然后获得的最大利润!
因此,我们需要两个关键值,一个是最小的买入值buy,另一个是最大的利润sell!
public int maxProfit(int prices[]) {
int sell = 0;
int buy = -prices[0];//假设第一天买了
for (int i=1;i<prices.length;i++){
sell = Math.max(sell,buy+prices[i]);//不持有,即该天的卖出,求最大利润,卖出所以是加价格
buy = Math.max(buy,-prices[i]);//持有,即当天买入,就负的价格 -prices,
// 最小买入,因为buy是负的,所以其最大就是价格最小
}
return sell;
}
给定一个数组 prices ,其中prices[i] 是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
122 题限制:交易次数无限制 k = +infinity
这是经典贪心算法。
public int maxProfit2(int prices[]) {
int resSell = 0;
for (int i=0;i<prices.length-1;i++){
int tmp = prices[i+1]-prices[i];//卖出前必须买入。则后一天减前一天
if(tmp>=0){//大于0,表示此次交易为正,可进行交易
resSell+=tmp;//利润加入总和
}
}
return resSell;
}
也可以使用跟121题
类似的方法
public int maxProfit2(int prices[]) {
int sell = 0;
int buy = -prices[0];//假设第一天买了
for (int i=1;i<prices.length;i++){
sell = Math.max(sell,buy+prices[i]);不持有,即该天的卖出,求最大利润,卖出所以是加价格
buy = Math.max(buy,sell-prices[i]);//持有,即当天买入,就负的价格 -prices,
//又因为该天不持有时sell可能不为0,所以考虑总的收益所以得加入sell-价格
}
return sell;
}
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成两笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
在任意一天结束之后,我们会处于以下五个状态中的一种:
1.未进行过任何操作;
2.只进行过一次买操作;
3. 进行了一次买操作和一次卖操作,即完成了一笔交易;
4.在完成了一笔交易的前提下,进行了第二次买操作;
5.完成了全部两笔交易。
由于第一个状态的利润显然为 0,因此我们可以不用将其记录。对于剩下的四个状态,我们分别将它们的最大利润记为buy1,sell1,buy2,sell2
//注意最后一次交易持有时考虑第一次交易的sell
public int maxProfit3(int prices[]) {
int n = prices.length;
int sell1 = 0;//dp[i][2][0]
int buy1 = -prices[0];//第一次交易的dp[i][2][1]
int sell2 = 0;//dp[i][1][0]
int buy2 = -prices[0];//第2次交易的dp[i][1][1]
for (int i= 1;i<n;i++ ){
sell2 = Math.max(sell2,buy2+prices[i]);//最后一次交易(不持有)
buy2 = Math.max(buy2,sell1-prices[i]);//最后一次持有,因为该天不持有时,有第一次交易sell1的值,所以带入
sell1=Math.max(sell1,buy1+prices[i]);//第一次交易(不持有)
buy1 = Math.max(buy1,-prices[i]);//第一次持有,sell为0,所以0-prices[i]
}
return sell2;//最后交易后的利润为总利润
}
给定一个整数数组prices ,它的第 i 个元素prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
public int maxProfit4(int k,int prices[]) {
if(prices.length==0){
return 0;
}
int n = prices.length;
k = Math.min(k,n/2);//k最大为总天数的一半
int[] buy = new int[k+1];
int[] sell = new int[k+1];
buy[0] = -prices[0];//交易前的买入
sell[0] = 0;//交易前的利润为0
for (int i =1;i<=k;i++){//初始K次交易,为最小。防止越界
buy[i] = sell[i]= Integer.MIN_VALUE/2;
}
for(int i=1;i<n;++i){//遍历价格,开始交易
buy[0] = Math.max(buy[0], sell[0] - prices[i]);//确定交易前的最小买入
for (int j = 1; j <= k; ++j) {//开始k次交易
buy[j] = Math.max(buy[j], sell[j] - prices[i]);//第j次买入的最小
sell[j] = Math.max(sell[j], buy[j - 1] + prices[i]);//第j次交易的利润
}
}
return Arrays.stream(sell).max().getAsInt();
}
给定一个整数数组,其中第i个元素代表了第i天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
存在冷冻期,就要考虑冷冻期的利润和不在冷冻期的利润
public int maxProfit5(int[] prices) {
if (prices.length == 0) {
return 0;
}
int n= prices.length;
int buy = -prices[0];//手上持有股票的最大收益
int sellC = 0;//手上不持有股票,并且处于冷冻期中的累计最大收益
int sellO =0;//手上不持有股票,并且不在冷冻期中的累计最大收益
for (int i =1;i<n;i++){
int newbuy = Math.max(buy,sellO-prices[i]);//该天持有(今天买入才会持有,当前应该执行买入)=前一天持有不操作 和 前一天不持有买入
// (前一天不持有的话,前一天就是冷冻期,那么今天就不再冷冻期,就用不在冷冻期最大利润-价格)
int newsellC = buy+prices[i];//该天冷冻期利润(交易后才是冷冻期,当前应该进行卖出) = (今天是冷冻期那么肯定是交易后变冷冻)buy+卖出价格
int newsellO =Math.max(sellC,sellO);//该天不在冷冻期(那么当前肯定是冷冻,当前冷冻不进行操作) = (今天不是冷冻期,由冷冻期过后才解冻)应该跟冷冻期比较获得最大利润
buy =newbuy;
sellC=newsellC;
sellO=newsellO;
}
return Math.max(sellC,sellO);
}
给定一个整数数组prices,其中第i个元素代表了第i天的股票价格 ;整数fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续
无限次交易次数,但是每次卖出有手续费!
//当我们卖出一支股票时,我们就立即获得了以相同价格并且免除手续费买入一支股票的权利
public int maxProfit6(int[] prices, int fee) {
if (prices.length==0){
return 0;
}
int n = prices.length;
int buy = prices[0]+fee;//买入的价格和即将卖出的手续费
int profit =0;//总收益
for (int i =1;i<n;i++){
if(prices[i]+fee <buy){//当前买入价格更低,则更换买入时机
buy = prices[i]+fee;
}else if(prices[i]>buy){//当前价格大于买入价格,证明收益为正,则卖出
profit+=prices[i]-buy;
buy = prices[i];//假设又买入,准备下次比较
}
}
return profit;
}