题目描述
给定一个数组 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 * 104
0 <= prices[i] <= 104
思路
这里我们需要注意交易人有两种状态
- 手里已经有一支股票了,根据题目意思,他之后进行的操作只能是卖出这支股票
- 手里没有股票,那么他之后的操作就是选择一支股票卖出去
根据这两种情况,我们可以写出两种方案:
- 暴力搜索
- 动态规划
我们知道,动态规划就是为了避免多余的操作的,我们在进行暴力搜索的时候有些情况进行了多次,而动态规划其实就是要将这些重复的操作结果记录下来,以便下次直接使用。
暴力搜索
以[1,2,3,4]为例,下面是暴力搜索的树形图
我们要注意设置状态的判别
- 如果手里有股票,我们得选择一个时间点卖出去,相应的收入就增加了price[i]
- 如果手里没有股票,则需要选择一个时间点买入,相应的收入就减少了price[i]
代码如下:
class Solution {
int max=0;
public int maxProfit(int[] prices) {
//选择买与卖
int len = prices.length;
if(prices.length<2){
return max;
}
//用dfs
dfs(0,prices, 1,0);
return max;
}
public void dfs(int cur,int prices[],int flag,int sum){
if(cur>prices.length){
return;
}
if(cur==prices.length){
if(sum>max){
max=sum;
}
return;
}
dfs(cur+1,prices,flag,sum);//向前移动
//手里已经有一个股票了,得选择卖出去
if(flag==0){
dfs(cur+1,prices,1,sum+prices[cur]);
}else if(flag==1){
//手里没得股票,得买一个
dfs(cur+1,prices,0,sum-prices[cur]);
}
}
}
但是这种方法是超时的,因为数量量比较大。
动态规划
动态规划主要是找到状态转移方程,我们可以根据交易人的状态来进行设置。
我们可以定义一个数组dp[i][j]表示在第i个时间点交易人处于第j种状态时的最大收益。这里我们只有两种状态,则j=0或者1
dp[i][0]表示交易人手里没有股票,dp[i][1]表示交易人里面有股票
dp[i][0]的值取决于上一个时间点,如果是上一个时间点卖的股票,则值为上一个时间点有股票的利益最大值加上卖出这张股票后的和;如果在更早之前买了,就等于上一个时间点没有股票时的利益最大值。然后取这两种最大值。
dp[i][1]与此类似。
相应的,我们可以写出状态转移方程:
dp[i][0]=max(dp[i-1][0],dp[i-1][1]+price[i]);
dp[i][1]=max(dp[i-1][1],dp[i-1][0]-price[i]);
我们也要注意初始值,dp[0][0]=0
dp[0][1]=-prices[0],因为买了这一支股票
代码:
class Solution {
public int maxProfit(int[] prices) {
//选择买与卖
int len = prices.length;
//dp[i][0]与dp[i][1]
//dp[i][0]表示第i支股票时已经卖出股票后利益的最大值
//dp[i][1]表示第i支股票时没有卖出股票后利益的最大值
int dp[][] = new int[len][2];
dp[0][0]=0;
dp[0][1]=-prices[0];
for(int i=1;i<len;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[len-1][0];
}
}