LC-买卖股票最佳时机

LC-买卖股票最佳时机

链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/
描述
给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

例1
输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。

例2输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

前言:一开始我看这题属于动态规划,直接想着二维数组求解,先画下数组再写代码,写完提交,发现内存超出限制,想着二维太大,进行降维,降成一维后提交,显示时间超时了,把代码优化了一下,还是超时,所以肯定是两次嵌套循环太耗时,只能想着用一次遍历去解决了。下面来看看代码的进化之路。

解法一:二维数组

  价格 7	   1     5    3    6     4
  收益-7   -6    -2   -4   -1    -3
  	  0   -1     4    2    5     3
 	  0    0    -5   -2    1    -1
 	  0    0     0   -3    3     1
 	  0    0     0    0   -6    -2
      0    0     0    0    0    -4

说明:第一行是每天股票的价格。第二行是第一天买入股票然后每天卖掉得到的收益,如第一天买入,收益-7,第二天卖掉就是第二天的价格-买入的价格=1-7=-6;第三天卖掉得话,就是5-7 = -2。
第三行是第二天买入股票的情况,第一天不买不卖,收益为0;第二天买入,收入为-1,;第三天卖掉的收益=第三天的价格-买入的价格=5-1=4,以此类推。
计算公式:比如第一行第三列:是等于当天的价格5,减去买入的价格7,第二行第三列:当天价格5,减去买入的价格1,怎么知道买入的价格?所在第几行那么第几列就是它买入的价格,第二行的价格就是第二列的价格。
公式:profits[i][j] = profits[i][i] + prices[j]
收益 = 第i行第i列的收益(买入时的收益)+当天价格

    public int maxProfit(int[] prices) {
    	//创建二维数组
        int[][] profits = new int[prices.length][prices.length];
        //将当天买入股票时收益初始化
        for (int i = 0; i < prices.length; i++) {
            profits[i][i] = 0 - prices[i];
        }
        //记录最大收益
        int max = 0;
        //开始循环处理
        for (int i = 0; i < prices.length; i++) {
            for (int j = i + 1; j < prices.length; j++) {
                profits[i][j] = profits[i][i] + prices[j];
                //从当前最大收益和当天卖掉获得的收益中取最大值作为最大收益
                max = Integer.max(max, profits[i][j]);
            }
        }
        return max;
    }

解法二:一维数组
二维数组需要空间太大,当数组很大时直接超出空间限制了,就接着降成一维数组,思路没怎么变。

    public int maxProfit(int[] prices) {
        int[] profits = new int[prices.length];
        int max = 0;
        for (int i = 0; i < prices.length; i++) {
            for (int j = i; j < prices.length; j++) {
            	//相当于解法一的买入时的收益初始化
                if (i == j) {
                    profits[j] = 0 - prices[j];
                } else {
                    profits[j] = profits[i] + prices[j];
                }
                max = Integer.max(max, profits[j]);
            }
        }
        return max;
    }

解法三:两次遍历
解法二超时,我以为是数组太大引起,直接不要数组了。

    public int maxProfit(int[] prices) {
        int max = 0;
        //两次遍历,就是买入然后看每天卖掉的收益,这种可能更方便理解点
        for (int i = 0; i < prices.length; i++) {
            for (int j = i; j < prices.length; j++) {
                max = Integer.max(max, prices[j]-prices[i]);
            }
        }
        return max;
    }

解法四:一次遍历
虽然解法三代码少了许多,思路也比较容易理解,暴力解决,但是还是超时,所以就是嵌套循环导致的,只能用一次遍历来求解了。
其实要获取最大的收益,一般来说就是买入时最便宜,卖出时最贵,我们可以遍历选择便宜的,然后求收益。注意:最后的计算得出最大收益时的最小价格并不一定是是真正的最小价格,例如:

9,3,12,1,4

可以看到12-3是最大的收益,但是最小的价格其实是1,代码中每次会将当前最大收益和此次收益对比,所以就算最小价格赋值为了1,最后计算的最大收益是没影响的。

    public int maxProfit(int[] prices) {
    	//先将最小价格设置为无穷大
        int minprices = Integer.MAX_VALUE;
        int max = 0;
        for (int i = 0; i < prices.length; i++) {
        	//如果当前价格低于最小价格,就将当前价格赋值给最小价格
            if (prices[i] < minprices) {
                minprices = prices[i];
            } else {
            	//计算收益,当前价格-最小的价格
                max = Integer.max(max, prices[i] - minprices);
            }
        }
        return max;
    }

你可能感兴趣的:(数据结构与算法,数据结构,动态规划)