剑指 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 };

 

posted @ 2021-11-29 18:04  不乏理想的三师弟  阅读(20)  评论(0)    收藏  举报