股票的最大利润 (DP求解)
题目描述:假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?LeetCode链接
题目分析:根据示例,我们发现需要找出给定数组中两个数字之间的最大差值(即,最大利润)。此外,第二个数字(卖出价格)必须大于第一个数字(买入价格)。
暴力求解
假设共有n天,第i天买入,第j天卖出,并且卖出价格必须大于买入价格,所以依次以第1天买入,第2 3 4….n天卖出,第2天买入,第3 4 5 6 …n天卖出,找出其中的最大值即可。
/**
* 暴力法
* @param prices
* @return
*/
public int maxProfit(int[] prices)
{
//定义变量保存最大值,初值为0
int max = 0;
//临时变量,记录第j天卖出的价格
int gain;
//假设第i天买入,第j天卖出
for (int i = 0; i < prices.length - 1; i++)
{
for (int j = i + 1; j < prices.length; j++)
{
//第i天买入,第j天卖出所赚的钱
gain = prices[j] - prices[i];
//找到最大值
if (gain > max)
{
max = gain;
}
}
}
return max;
}
动态规划求解
分析:假设dp[i]第i天的最大利润
我们想要求第i天的最大利润,我们就需要知道 前一日的最大利润dp[i-1] 和 第i天的卖出的最大利润中的最大值prices[i]-min[0,i] ,这两个值谁大,谁就是第i天的最大利润。
prices[i]-min[0,i] 解释:prices[i]为当天卖出价格 ,min[0,i]为前i日最低价格,这样就是当天的最大利润了
因此 转移方程为:dp[i]=Max(dp[i-1],prices[i]-min[0,i])
综上,代码如下
public static int maxProfit(int[] prices)
{
int[] dp = new int[prices.length];
int[] minCost = new int[prices.length];//记录前N天中的最小值
int min = Integer.MAX_VALUE;
//创建记录前i天最小买入价格的数组
for (int i = 0; i < prices.length; i++)
{
if (prices[i] < min)
{
min = prices[i];
}
minCost[i] = min;
}
//动态规划构造dp数组
for (int i = 1; i < prices.length; i++)
{
min = Math.min(minCost[i], prices[i]);
dp[i] = Math.max(dp[i - 1], prices[i] - min);
}
//找出dp数组中的最大值
int max = 0;
for (int i = 0; i < dp.length; i++)
{
if (max < dp[i])
{
max = dp[i];
}
}
return max;
}
优化动态规划
-
对于前i天的最低价格min[0,i],可以在dp循环中,使用一个变量minCost来记录即可
优化后转移方程为:dp[i]=Max(dp[i-1],prices[i]-minCost)
-
由于dp[i]只与dp[i-1] prices[i] minCost有关,因此用一个变量max替换dp数组即可
优化后的转移方程为:max=Max(max,prices[i]-minCost)
综上,代码如下
public int maxProfit2(int[] prices)
{
int minCost = Integer.MAX_VALUE;//记录前N天中的最小值
int max = 0;
for (int i = 0; i < prices.length; i++)
{
minCost = Math.min(minCost, prices[i]);//如果当天的最值小于之前的最小值,那么更新最小值
max = Math.max(max, prices[i] - minCost);//比较昨天的最大利润和今天的最大利润,其中最大值为今天的最大利润
}
return max;
}