🐕给定一个数组 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 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
提示:
- 1 <= prices.length <= 3 * 10的4次方
- 0 <= prices[i] <= 10的4次方
思路:
动态规划解法思路:定义一个二维数组 dp
dp[i][0]表示第 i+1 天交易完之后手里 没有股票 的最大利润
dp[i][1]表示第 i+1 天交易完之后手里 持有股票 的最大利润。
🐖版本一:
当天交易完之后手里 没有股票 的两种情况
1)前一天 手里也没有股票 dp[i-1][0] 今天又没买
2)前一天 手里有股票 但是在 今天 才 卖出去了dp[i-1][1] + prices[i]
取两者最大值
当天交易完之后手里 持有股票 的两种情况
1)前一天 手里就持有股票 所以今天 持久旧股票 (不能买入新的) dp[i-1][1]
2)前一天 手里没有股票 所以 今天 买了新股票 dp[i-1][0] - prices[i]
取两者最大值
最后返回的是 最后一天手里没有股票的情况 即dp[prices.length-1][0]
上代码
public static int dp_ways1(int[] prices) {
if(prices.length < 2 || prices == null) {
return -1;
}
//定义一个二维数组 dp
int[][] dp = new int[prices.length][2];
/*
对数组的第一列初始化
dp[0][0] 表示手中无股票 所以 为 0
dp[0][1] 表示 购买了股票 所以 用 - prices[0] 来表示当天购买股票的钱数
*/
dp[0][0] = 0;
dp[0][1] = - prices[0];
/*
接下来 从 第二列开始遍历
当天交易完之后手里 没有股票 的两种情况
1)前一天 手里也没有股票 dp[i-1][0] 今天又没买
2)前一天 手里有股票 但是在 今天 才 卖出去了dp[i-1][1] + prices[i]
取两者最大值
当天交易完之后手里 持有股票 的两种情况
1)前一天 手里就持有股票 所以今天 持久旧股票 (不能买入新的) dp[i-1][1]
2)前一天 手里没有股票 所以 今天 买了新股票 dp[i-1][0] - prices[i]
取两者最大值
最后返回的是 最后一天手里没有股票的情况 即dp[prices.length-1][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];
}
🐖版本二:对版本一 进行优化
当天的利润只和前一天有关,所以无需使用一个二维数组
只需要使用两个变量
一个记录当天交易完之后手里 持有股票的最大利润
一个记录当天交易完之后手里 没有股票的最大利润
当天交易完之后手里 没有股票 的两种情况
1)前一天 手里也没有股票 dont 今天又没买
2)前一天 手里有股票 但是在 今天 才 卖出去了have + prices[i]
取两者最大值
当天交易完之后手里 持有股票 的两种情况
1)前一天 手里就持有股票 所以今天 持久旧股票 (不能买入新的) have
2)前一天 手里没有股票 所以 今天 买了新股票 dont - prices[i]
取两者最大值
最后返回的是 最后一天手里没有股票的情况 即dont
上代码
public static int dp_way2(int[] price) {
if(price.length < 2 || price == null) {
return 0;
}
/*
对have 和 dont 进行初始化
have 表示 当前交易后 持有股票的最大利润
dont 表示 当前交易后 没有股票的最大利润
*/
int have = - price[0];
int dont = 0;
/*
从第二列开始遍历
当天交易完之后手里 没有股票 的两种情况
1)前一天 手里也没有股票 dont 今天又没买
2)前一天 手里有股票 但是在 今天 才 卖出去了have + prices[i]
取两者最大值
当天交易完之后手里 持有股票 的两种情况
1)前一天 手里就持有股票 所以今天 持久旧股票 (不能买入新的) have
2)前一天 手里没有股票 所以 今天 买了新股票 dont - prices[i]
取两者最大值
最后返回的是 最后一天手里没有股票的情况 即dont
*/
for(int i = 1; i < price.length; i++) {
dont = Math.max(dont, have + price[i]);
have = Math.max(have, dont - price[i]);
}
return dont;
}
贪心算法解法思路
🐖版本三:贪心算法
看到如果股票一直上涨
只需要找到股票上涨的最大值和股票开始上涨的最小值
计算他们的差就是这段时间内股票的最大利润
如果股票下跌就不用计算
最终只需要把所有股票上涨的时间段内的利润累加就是我们所要求的结果
上代码
public static int greedy(int[] prices) {
if(prices.length < 2 || prices == null) {
return 0;
}
//res 为结果 、index 为当前数组指针 、 len 为数组长度
int res = 0, index = 0,len = prices.length;
// 当指针没越界时
while(index < len) {
//跳过 下跌
while(index < len -1 && prices[index] >= prices[index + 1]) {
index ++; // 指针继续 前进
}
//此时index位置开始要上涨了 先记录一下
int min = prices[index];
//跳过上涨
while(index < len -1 && prices[index] <= prices[index + 1]) {
index ++; // 指针继续 前进
}
//此时index 下一个位置开始下跌 当前为上涨最大值
//计算这一段上涨的差值 累加入 res
res += prices[index++] - min;
}
return res;
}