输入:一个数组prices,prices[i]表示第i天股票的价格。
输出:买卖股票的最大收益。
规则:只允许最多买一次,最多卖一次股票。如果觉得价格不合适,可以不买卖。
分析1:最先想到的是暴力搜索,每天都可以买或者卖,当然要符合规则。倒是AC了,但是时间太长。这个复杂度应该是2^n。
private int maxProfit;public int maxProfit(int[] prices) {maxProfit = 0;trasaction(prices,0,false,true,0);return maxProfit;}private void trasaction(int[] prices,int idx,boolean sell,boolean buy,int profit){if(idx==prices.length){maxProfit = Math.max(maxProfit,profit);}else{if(buy){trasaction(prices,idx+1,true,false,profit-prices[idx]);}else if(sell){maxProfit = Math.max(maxProfit,profit+prices[idx]);}trasaction(prices,idx+1,sell,buy,profit);}}
分析2:这是参考别的答案。只要找到最低成本minPrice,如果其下标为i,只要j>i,prices[j]-minPrice就是收益。各个收益取最大值。这是技巧问题,背多次,形成这样的思维。
public int maxProfit(int[] prices) {int maxProfit = 0;int minPrice = Integer.MAX_VALUE;for(int i=0;i<prices.length;i++){minPrice = Math.min(minPrice,prices[i]);maxProfit = Math.max(maxProfit,prices[i]-minPrice);}return maxProfit;}
进阶题目122:可以多次买卖股票。但是得先买股票才能卖股票。如果已经买了股票,需要卖了,才能再买。
分析1:暴力购买。超时。
学习1:参考网页。收益profit是子收益sub-profit的和。在第i天购买,第j天卖,每个sub-profit是不同的。在[i,j]范围内我们该怎么选择才能让sub-profit最大呢?我们应该找到的j是在这个范围内prices[j]是尽可能大的那个值,i是在这个范围内prices[i]尽可能小的那个值。
举例来说。我们有数组[3,2,5]。我们会选择[2,5],而不会选择[3,5],因为2<5。
如果数组[3,2,5,8],我们会选择[2,8],因为5<8。
从这两个例子,我们观察到我们选择购买的那个x应该是一个连续值中的最小值。我们卖出去的那个y应该一个连续序列中的最大值。
再举个例子。[3,2,5,8,1,9],虽然1是最小值,但是我们选择2,因为2是一个连续递减序列的最小值(从3开始)。同样虽然9是最大值,但是我们选择8。因为8是从2开始的连续递增序列的最大值。
实际上,[3,2,5,8,1,9]被分成了2个子数组,分别选择[2,8]和[1,9]。
public int maxProfitV2(int[] prices) {int maxProfit = 0;int i=0;int n = prices.length;while(i<n-1){while(i<n-1 && prices[i+1]<=prices[i]) i++;int buy = prices[i];while(i<n-1 && prices[i+1]>prices[i]) i++;int sell = prices[i];maxProfit += sell - buy;}return maxProfit;}