题目
- 买卖股票的最佳时机 传送门
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
思路分析
咋看这个题目很简单,但是越是这样的题越需要小心,因为往往这类看起来很简单的题目第一眼想出的答案都不是最优解,这个题目无非就是数组后面一个数组减去前面某个数字的差能够最大,求这个最大是多少。题目等价于 max(nums[j] - nums[i]) 并且 j > i。
第一眼思路可能会想到从右到左遍历数组,然后分别求出左边的最小值,然后向减。
复杂度分析: 很显然,这样双层循环时间复杂度为n2。
然而这个题目可以用更简单的方式,使用n级别的复杂度,很多同学可能会想到用动态规划去解决,其实先不说状态转移方程如何推导的问题,动态规划的空间复杂度就是n,其实也不够好。我们只要最大值就好。
我们可以一边遍历,一边记录最小值min,并且用当前nums[i] - min得到的值与当前计算的最大值max比较,如果大就替换当前max为这个差值,最后遍历结束,max即为所求结果。
复杂度分析: 时间复杂度为n,空间复杂度为1。
代码实现:
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) return 0;
int min = Integer.MAX_VALUE, max = 0;
for (int i = 0;i < prices.length;i ++) {
min = Math.min(prices[i], min);
max = Math.max(prices[i] - min, max);
}
return max;
}
注意边界条件的处理,自测的时候尽量多跑几个边界case,争取一次性提交bug free的代码。