leetcode-数组-简单-买卖股票的最佳时机

题目

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。注意:你不能在买入股票前卖出股票

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

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

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

解答

方法一:

我刚一开始分析这个题,觉得题目就是这样的特征

  • 找到数组中两个数的差值最大
  • 后边的数要比前边的数大

直接思路就是循环每一个元素,然后拿这个元素前边的元素和这个数挨个进行差值,找到最大值,返回的时候判断一下是否大于0

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        int res_max = prices[1] - prices[0];
        for (int i = 2; i <prices.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (prices[i] - prices[j] > res_max) {
                    res_max = prices[i] -prices[j];
                }
            }
        }
        return res_max > 0 ? res_max : 0;
    }
};

一运行,超出时间限制,看来暴力方法越来越不让用了。

 可是又不想放弃这个思路,我觉得这个很合理啊,一般第一反应大家都会这么想吧,为了得到提交结果,我想暴力方法肯定是多算了不少东西,看看尝试优化一下。

  • 第一把默认最大值设为0,这样不用返回的时候每次进行一次三元运算,而且中间的数据判断碰到负数也不用进入if内部。
  • 第二因为每个元素都会把之前的全部计算完一遍差值,那么在计算下一个元素的时候,如果下一个元素比这个元素小,是没有计算的必要的,因为小的话,假设这个元素位置最大差值变了,那么上一个元素比它大,肯定差值更大,那必然会提前计算出来,这个位置的计算也是没有必要的。加上这个判断应该能减少不少循环。
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        int res_max = 0;
        for (int i = 1; i < prices.size(); ++i) {
            ///这种情况不要计算,因为如果i + 1 产生最大差值,
            ///那么 i的差值一定更大,肯定提前就计算完成了
            if (prices[i] <= prices[i - 1]) {
                continue;
            }
            for (int j = 0; j < i; ++j) {
                if (prices[i] - prices[j] > res_max) {
                    res_max = prices[i] -prices[j];
                }
            }
        }
        return res_max;
    }
};

果然这种方案没有超时。 

方法二:

又想了一个方案看看能不能一次循环搞定。

  • 标记一个买点位置,一个卖点位置,然后让他们移动
  • 卖点位置一定在买点位置后边
  • 如果出现比买点小的值,那么应该移动买点
  • 如果出现比卖点大的值,那么应该移动卖点
  • 每次都计算买点和卖点的差值,就可以找出最大值了
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        //假设差值最大的位置f_n 
        int res_max = prices[1] - prices[0];
        int buy_index = 0, sell_index = 1;
        for (int i = 1; i < prices.size(); i++) {
            // 发现有比买点小的,就移动买点
            if (prices[buy_index] > prices[i]) {
                buy_index = i;
            }
            //发现有比卖点大的 就移动卖点
            if (prices[sell_index] <= prices[i]) {
                sell_index = i;
            }
            if (sell_index < buy_index) {
                //买点移动之后,卖点也要移动
                sell_index = buy_index;
                continue;
            }
            res_max = max(res_max, prices[sell_index] - prices[buy_index]);
        }
        return res_max;     
    }
};

方法三:

看了其他人的方法得到的答案

思路应该大致和方法二相同,不过更简洁。

  • 记录最小值,只要最小值有变化就更新最小值。
  • 每一个元素都和最小值相减。比较大小。
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty() || prices.size() == 1) {
            return 0;
        }
        int res_max = 0;
        int min = prices[0]; //记录过往的最小值
        for (int i = 1; i < prices.size(); i++) {
            if (prices[i] > min) {
                res_max = max(res_max, prices[i] - min);
            } else {
                min = prices[i];
            }
        }
        return res_max;     
    }
};

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章