[leetcode]Best Time to Buy and Sell Stock I, II, III

这三道与股票相关的题目很有意思,有一些常用的小tricky和代码简洁技巧都用到了。

第一题

Say you have an array for which the ith element is the price of a given stock on dayi.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

给一个股票价格序列,只能进行一次买卖,问最大收益是多少。

显然用i,j写个二重循环枚举买点和卖点,可以得到最大收益,是O(n^2)复杂度。


一个最容易想到的O(n)算法是:

1、首先计算 [0, i] 这个区间内的波谷(最低的价格),记为low[i]

2、然后用prices[i] - low[i] 这个就是 以prices[i]作为卖点时,可以获得的最大收益。

更新变量result = max(result, prices[i] - low[i]) 即可。

一个编程技巧是,因为第2步的计算与第一步中low[i]后面的值无关,因此可以写在一遍循环中。

而low[i] 也无需开一个数组来保存,只需要一个valley变量即可(因为i之前的low[i]值以后不会再用到,无需保存下来):


代码如下:

class Solution {
public:
    int maxProfit(vector &prices) {
        int n = prices.size();
        if (n == 0) return 0;
        int valley = prices[0];
        int i;
        int result = 0;
        for (i = 1; i < n; i++) {
            valley = min(valley, prices[i]);
            result = max(result, prices[i] - valley);
        }
        return result;
    }
};

第二题

Say you have an array for which the ith element is the price of a given stock on dayi.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

题目是说,可以任意次数买卖。

那显然要把所有“上升”道路全都吃掉,才能使收益最大。

因此直接一遍循环,判断当前价格大于上一时间,则直接累加到结果中。

class Solution {
public:
    int maxProfit(vector &prices) {
        int n = prices.size();
        if (n == 0) return 0;
        int last = prices[0];
        int i, j;
        int sum = 0;
        for (i = 1; i < n; i++) {
            if (prices[i] > last) {
                sum += (prices[i] - last);
            }
            last = prices[i];
        }
        return sum;
    }
};


第三题

Say you have an array for which the ith element is the price of a given stock on dayi.

Design an algorithm to find the maximum profit. You may complete at mosttwo transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

这道题目限制了购买次数(至多买卖两次)

可以遍历i,以i作为分割点,分为[0, i] 和 [i, n-1],将两边的最大的单次购买收益加起来,作为以i为分割点时的最大收益。

遍历i,即可得到该题的最大收益。


这里需要用到第一问的一些技巧:

可以在同一循环内:更新波谷变量,更新left[i]数组([0, i]的最大单次购买收益。这个必须要用数组存,因为后面还要用到前面的计算结果)

当然right[i] ([i, n-1]的最大单次购买收益)这个就不必用数组存了,因为可以在循环过程中更新result,后面不会再用到)

也可以在同一循环内更新right[i] 和 result结果

class Solution {
public:
    int maxProfit(vector &prices) {
         vector  left(prices.size(), 0);
         int right = 0;
         int n = prices.size();
         int i;
         if (n == 0) return 0;
         int valley = prices[0];
         int heap = prices[n-1];
         for (i = 1; i < n; i++) {
             valley = min(valley, prices[i]);
             left[i] = max(left[i-1], prices[i] - valley); //这里prices[i] - valley 可以在同一循环中计算
         }
         int result = 0;
         for (i = n-2; i >= 0; i--) {
             heap = max(heap, prices[i]);
             right = max(right, heap - prices[i]); //用一个right变量即可
             if (right + left[i] > result) {
                 result = left[i] + right;
             }
         }
         return result;
    }
};


你可能感兴趣的:(leetcode)