目录
一、需求
A:给定一个数组,它的第i个元素是一支给定股票第i天的价格;
B:设计一个算法计算能获取的最大利润,可以尽可能完成更多交易(多次买卖一支股票);
C:注意你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)
二、暴力递归法
2.1 思路分析
A:假设prices = [7,1,5,3,4,6,...];
B:假设第1天买入,第2天卖出,则最大利润为prices[1]-prices[0]+[5,3,4,6,...]的最大利润;
C:假设第1天买入,第3天卖出,则最大利润为prices[2]-prices[0]+[3,4,6,...]的最大利润;
D:归纳推理
a:假设第i天买入,那么0 <= i < prices.length;
b:假设第j天卖出,那么i+1 < j < prices.length;
c:最大利润=prices[j]-prices[i]+calculate(prices,j+1);
E:递归的终止条件是什么呢?
a:上面D中c步骤是关键,j+1会当作参数传递给calculate方法,也就是每次递归,这个参数都要变大,
直到prices[j]是最后后一天时,j+1就是当前数组的长度,然后返回0;
F:递归的规律是什么呢?
a:当买入的价格低于要售出的价格时,开始递归,规律就是D中的c,并更新在某一天买入时,能获得的
最大利润;
G:比较每天买入能够获得的最大利润,并更新;
H:注意,递归太深的话,响应会超时;
2.2 代码实现
class Solution {
public int maxProfit(int[] prices) {
return calculate(prices, 0);
}
//定义方法
public int calculate(int[] prices,int s) {
int max = 0;
//递归的终止条件
if(s >= prices.length) {
return 0;
}
for(int i = s; i < prices.length; i++) {
//更新某天买入能获得的最大利润
int maxprofit = 0;
for(int j = i+1; j < prices.length; j++) {
if(prices[i] < prices[j]) {
int profit = calculate(prices,j+1)+prices[j]-prices[i];
if(profit > maxprofit) {
maxprofit = profit;
}
}
}
if(maxprofit > max) {
max = maxprofit;
}
}
return max;
}
}
2.3 复杂度分析
A:时间复杂度为O(n^n),调用递归函数n^n方次;
B:空间复杂度为O(n),递归调用的深度为n;
三、峰谷法
3.1 思路分析
A:因为交易次数可以是多次,故最大利润=多次交易的(波峰-波谷)的和;
B:使用i来遍历天数,i从0开始,考虑到在确定波谷/峰的时候,需要比较prices[i]和prices[i+1],
那么i最多只能遍历到倒数第2天,也就是0<=i<prices.length-1;
C:既然要确定连续的波谷波峰,那就需要采用循环的方式,找到那个最低的谷;
a:当前第i天的价格要高于第i+1天的价格,则i++;
b:i最多遍历到倒数第2天,不然假设遍历到倒数第2天,i++后,数组就越界了;
3.2 代码实现
public int maxProfit(int[] prices) {
//定义相关变量
int profit = 0;
int i = 0;
int valley = 0;
int peak = 0;
//寻找波谷和波峰,并求最大利润
while(i < prices.length - 1) {
//找到连续的谷和峰
//找到波谷
while(i < prices.length - 1 && prices[i] >= prices[i+1]) {
i++;
}
valley = prices[i];
//找到波峰
while(i < prices.length - 1 && prices[i] <= prices[i+1]) {
i++;
}
peak = prices[i];
//更新最大利润
profit += peak - valley;
}
return profit;
}
3.3 复杂度分析
A:因为从头到尾,是i从0遍历到了倒数第二个元素,所以时间复杂度为O(n);
B:只使用了常量的空间,空间复杂度为O(1);
四、峰谷法改进(贪心算法)
4.1 思路分析
A:在峰谷法的基础上,我们把每一次寻找到的连续的谷和峰分解成了很多小段;
B:在求谷的过程中,可能连续2天都在下降,在求峰的过程中,可能连续3天都在上升;
C:利用循环,从第1天开始,到最后一天,1<=i<prices.length;
a:若第i天的价格要大于前1天的价格,那就说明有利可图,相当于波谷到波峰上升的那一段;
b:然后到了波峰到波谷下降的一段,没啥利润了,就直接对i++;
c:然后再从波谷到波峰,这样结束后,最大利润也就出来了;
4.2 代码实现
public int maxProfit(int[] prices) {
int profit = 0;
for(int i = 1; i < prices.length; i++) {
if(prices[i] > prices[i-1]) {
profit += prices[i] - prices[i-1];
}
}
return profit;
}
4.3 复杂度分析
A:时间复杂度为O(n);
B:只使用了常量的空间,空间复杂度为O(1);
五、动态规划法
5.1 思路分析
A:目前分析不出来;
5.2 代码实现
public int maxProfit(int[] prices) {
int len = prices.length;
//len为1或0,最大利润为0
if (len < 2) {
return 0;
}
// 0:持有现金
// 1:持有股票
int[][] dp = new int[len][2];
dp[0][0] = 0;
dp[0][1] = -prices[0];
for (int i = 1; i < len; i++) {
//第i天持有现金=昨天就持有的现金 或者 将昨天的股票在今天卖出得到的现金 的最大值
dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
//第i天持有股票=昨天就持有股票 或者 用昨天的现金在今天买入股票 的最大值;
dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
}
return dp[len - 1][0];
}
5.3 复杂度分析
A:时间复杂度为O(n);
B:二维数组的第二维是常量,空间复杂度为O(n);
六、参考地址
来源:CSDN
作者:皮卡qiu~
链接:https://blog.csdn.net/Sruggle/article/details/104127271