剑指 Offer 63. 股票的最大利润
题目链接:https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof/
本文采用JavaScript进行解题:一、暴力法 二、不知道叫什么法【更优】 三、一次遍历【更更优】
一、暴力法
算法时间复杂度:O(n^2)

1 var maxProfit = function (prices) { 2 let maxProfit = 0; 3 // i:小值下标,j:大值下标 4 for(let i = 0; i < prices.length; i++) { 5 for(let j = i; j < prices.length; j++) { 6 let profit = prices[j] - prices[i]; 7 if(profit > maxProfit) maxProfit = profit; 8 } 9 } 10 return maxProfit; 11 };
二、不知道叫什么法【更优】
约定数组的下标为日数,数组值为股票价值。
规则:抛售日必须大于入手日;
现在有两个方向获取可能的最大利润:
- 第一个就是在最高价值时抛售
- 第二个就是在最低价值时入手
有一点可以确定的:不会再价值下降的阶段入手,至少在第一个价值上升的开始进行操作(start日)
- 在选择在最高价值抛售时,入手日必须在抛售日之前,而为最大利润,应在[start日,最高价值日)中选择最小价值的那天入手。
- 在选择在最低价值入手时,抛售日必须在入手日之后,而为了最大利润,应在入手日以后的时间[最低价值日,最后一天]选择最高价值的那天抛售。
比较两种决策所获的利润,利润大的就为最有决策。
算法时间复杂度:O(n)

1 /** 2 * @param {number[]} prices 3 * @return {number} 4 * 目的:确认最大利润 5 * 第一步:找出数组的第一个起势点(起势点:即下一点会上升的点) 6 * 第二步:在[起势点,length-1]范围内确认最大值索引(max)、最小值索引(min) 7 * 第三步:在[起势点,最大值索引)范围中找出最小值索引 8 * 第四步:在[最小值索引,length-1]范围中找出最大值索引 9 * 第五步:在两个可能结果(最大值与最大值左半区间中的最小值的差、最小值与最小值右半区间中的最大值的差),中挑选最优结果(利润最大值)。 10 */ 11 var maxProfit = function (prices) { 12 if(prices.length === 0) return 0; 13 let start = 0; 14 let length = prices.length; 15 while (prices[start] >= prices[start + 1]) { 16 start++; 17 // 没有起势点,即最大利润为0 18 if (start + 1 > length) return 0; 19 } 20 let startLimitArray = prices.slice(start); 21 // 数组中最大值的最后一个索引 22 let max = prices.lastIndexOf(Math.max(...startLimitArray)); 23 // 数组中最小值的第一个索引 24 let min = prices.indexOf(Math.min(...startLimitArray)); 25 // 最大值的前部分数组 26 let maxLimitArray = prices.slice(start, max + 1); 27 // 最小值的后部分数组 28 let minLimitArray = prices.slice(min); 29 // 在最大值的前部分数组中找出最小值,并算出最大值与该最小值的差(利润) 30 let profit1 = prices[max] - Math.min(...maxLimitArray); 31 // 在最小值的后部分数组中找出最大值,并算出最小值与该最大值的差(利润) 32 let profit2 = Math.max(...minLimitArray) - prices[min]; 33 return Math.max(profit1, profit2); 34 };
三、一次遍历【更更优】
与这种方法比较,可以发现第二种方法很多地方都是多余的;
在不断确定新的最低点的过程中,不断更新最优利润(最低点与高点的差);
该方法巧妙之处是无论最低点在最高点之前还是之后都没有影响,因为每轮都可能更新最大利润,即使最高点后有更低点也可以再度更新最大利润。
算法时间复杂度:O(n)

1 /** 2 * @param {number[]} prices 3 * @return {number} 4 */ 5 var maxProfit = function (prices) { 6 let minPrice = Number.MAX_VALUE; 7 let maxProfit = 0; 8 for (const price of prices) { 9 maxProfit = Math.max(price - minPrice, maxProfit); 10 minPrice = Math.min(price, minPrice); 11 } 12 return maxProfit; 13 };

浙公网安备 33010602011771号