题目描述
假设你有一个数组,其中第 i 个元素是股票在第 i 天的价格。
你有一次买入和卖出的机会。(只有买入了股票以后才能卖出)。请你设计一个算法来计算可以获得的最大收益。
示例1
输入:[1,4,2]
返回值:3
题目分析
在只有一次买入和卖出的机会的情况下,选择第 i 天买入,第 j 天卖出,则收益为 prices[j]-prices[i],需要找到能够获得的收益最大值,如下图,计算出的最大值是3。
解题思路
方法1:暴力法
暴力遍历数组从 i 到 j (0<=i<j<n)的收益值(prices[j]-prices[i]),使用max记录出现的最大收益值;
想要遍历所有的i和j,需要两次遍历;
for(int i){ for(int j){ } }
方法2:动态规划
使用动态规划数组dp,dp[i]表示前i天能够收益的最大值;
状态转移方程为: dp[i] = Math.max(dp[i-1], dp[i]-min);
这里面需要使用min,记录出现过的最小价格。
代码实现
方法1:暴力法
public int maxProfit (int[] prices) { // write code here // 默认收益为0 int max = 0; for(int i=0;i<prices.length;i++){ for(int j=i+1;j<prices.length;j++){ int profit = prices[j] - prices[i]; // 当收益大于记录的值时,更新最大收益 if(profit > max){ max = profit; } } } return max; }
时间复杂度:O(n^2),n为数组的长度,两层循环的事件复杂度为n^2;
空间复杂度:O(1),只需要常数的变量记录中间值和最大利益值;
方法2:动态规划
public int maxProfit (int[] prices) { // write code here if(prices == null || prices.length == 0) return 0; int len = prices.length; // 动态规划数组 int dp[] = new int[len]; int min = prices[0]; for(int i=0;i<prices.length;i++){ // 更新在i前的最小值 if(prices[i] < min){ min = prices[i]; } if(i == 0){ dp[i] = 0; }else{ // 状态转移方程,dp[i]的值在dp[i-1]和(当前值-当前最小值)中的最大值 dp[i] = Math.max(dp[i-1], prices[i]-min); } } // 返回最后的结果 return dp[len-1]; }
时间复杂度:O(n),只需要遍历一遍数组;
空间复杂度:O(n),需要n长度的辅助动态数组来帮助计算。