在一天内买卖股票

时间:2012-02-09 14:06:02

标签: algorithm

我在接受采访时被问到这个问题:

Best Time to Buy and Sell Stock

假设您有一个数组,其中第i个元素是第i天给定股票的价格。 如果您只被允许购买一股股票并卖出一股股票,那么设计一种算法来寻找买卖的最佳时机。我能够给出O(n)算法。

虽然面试官问我一个问题,但是“买一个,卖一个”,然后“买一个,卖一个”是什么情况,这意味着一天有两笔交易,最大化利润。我能够给出一个O(n ^ 2)算法。但采访者表示可以改进。有O(n)算法吗?

面试官说你不能同时买两份。你必须买一个卖,然后在另一个时间买一个,然后卖掉它。

3 个答案:

答案 0 :(得分:1)

原始问题reference中给出的O(n)解决方案为原始数组的每个前缀提供了最佳的“买一个然后卖出一个”答案。该算法也可以通过简单的修改来应对“向后”的情况;即从阵列向后工作的“卖一个然后买一个”;这相当于为阵列的每个后缀添加“买一送一”的答案。

现在,在“买入,卖出,买入,卖出”的情况下,我们有一点(在第一次卖出之后)我们在阵列中的某个位置,比如 b 。对于该断点,最佳解决方案是 0..b 的最佳前缀解决方案和 b + 1..n 的最佳后缀解决方案。最好的“买入,卖出,买入,卖出”是这些最佳解决方案的最佳选择。

因此,要解决 O(n)中的“买,卖,买,卖”,您可以在 O(n)中解释前缀,后缀为 O(n),然后为每个断点计算最佳值 - 所以 nO(1)。这是使用 O(n)空间的 O(n)算法。

答案 1 :(得分:0)

可以优化它只有一个for循环,但想法基本相同:

int maxProfit(vector<int> &prices) {        
    if (prices.empty()) return 0;        

    int n = prices.size();
    int lHolding = prices[0], rHolding = prices[n-1];
    int lMax = 0, rMax = 0;        

    vector<int> profit(n);

    for (int i = 1; i < n; i++) {            
        if (prices[i] > lHolding) {
            lMax = max(lMax, prices[i] - lHolding);
        } else {
            lHolding = prices[i];
        }

        profit[i] += lMax;

        int right = n - 1 - i;

        if (rHolding > prices[right]) {
            rMax = max(rMax, rHolding - prices[right]);
        } else {
            rHolding = prices[right];
        }

        profit[right] += rMax;            
    }

    return *max_element(profit.begin(), profit.end());        
}

答案 2 :(得分:0)

我迟到了比赛,但现在是。首先,由可怕的解决方案提供的解决方案并不十分清楚,因为有可能有人实现并得到O(n ^ 2)。这只是通过循环遍历b,对于每个b,计算前缀和后缀,每个都是O(n),所以它一起是O(n)*(n)其中(n)来自b = 1 ... n 。这意味着结果是O(n ^ 2)。

要实现该描述以使其在O(n)中运行,需要认识到前缀和后缀是独立的,并且可以由Daniel实现单独运行。

此解决方案的问题是它需要O(n)空间。假设您的库存跟踪是1千兆点(例如,如果您要重复使用2年的数据,则非常常见),那么您将耗尽内存使用量。

如果我是面试官,下一个合乎逻辑的问题是:是否可以删除内存要求?

让我试一试。其中大部分只是基础数学。

我们有一个数组价格[0 ... n-1]。

在原始问题中,我们希望找到r,s其中0&lt; = r&lt; s&lt; n这样

p =价格[s] - 价格[r]

最大化。

在新问题中,我们希望找到i,j,k,l其中0&lt; = i&lt; j&lt; k&lt; l&lt; n&lt; n

q =价格[j] -prices [i] +价格[l] -prices [k]

最大化。

(假设n> = 4,即没有退化情况,我们可以轻松处理)

假设我们解决了原问题,那么新问题的解决方案可分为3种情况:

  1. I =为r J = S&LT; K&LT;升
  2. I&LT; J&LT; K =为r升= S
  3. I =为r J&LT; K&LT;升= S
  4. 通过减少荒谬来证明这一点很容易(即假设没有,然后扰乱i或k到r和j或l到s。这种扰动会增加q,与原始假设相矛盾。)

    好的,解决方案很简单:

    一个。在O(n)中找到r,s 湾检查O(n)中的案例1 C。在O(n)中检查案例2 d。在O(n)中检查案例3 即返回b,c,d的最大值。

    实际上,b,c和d可以在n次迭代中执行。总共为2 O(n)+ O(1),其为O(n)。还有一些固定数量的变量,因此空间要求为O(1)。

    int maxProfit(vector<int> &prices) {        
        int n = prices.size();
    
        int b, a;
        int m1 = 0;
        int hb;
    
        b = a = 0;
        hb = 0;
        for (int i = 1; i < n; i++) {
            if (prices[i] < prices[hb]) {
                hb = i;
            }
            if (prices[i] - prices[hb] > m1) {
                m1 = prices[i] - prices[hb];
                b = hb; a = i;
            }
        }
    
        int before = 0, after = 0;
        if (b > 0) {
            int bb, ba;
            before = 0;
            int bhb;
    
            bb = ba = 0;
            bhb = 0;
            for (int i = 0; i < b-1; i++) {
                if (prices[i] < prices[bhb]) {
                    bhb = i;
                } 
                if (prices[i] - prices[bhb] > before) {
                    before = prices[i] - prices[bhb];
                    bb = bhb; ba = i;
                }
            }
        }
        if (a < n) {
            int ab, aa;
            int ahb;
    
            ab = aa = a+1;
            ahb = a+1;
            after = 0;
            for (int i = a+2; i < n; i++) {
                if (prices[i] < prices[ahb]) {
                    ahb = i;
                } 
                if (prices[i] - prices[ahb] > after) {
                    after = prices[i] - prices[ahb];
                    ab = ahb; aa = i;
                }
            }
    
        }
    
    
        int hmb = before + m1;
        int hma = after + m1;
        int hm = max(hmb,hma);
    
        int tm = b;
        for (int j = b+1; j < a; j++) {
            if (prices[j] > prices[tm]) {
                tm = j;
            }
            m1 = prices[tm] - prices[b] + prices[a] - prices[j];
            hm = max(hm,m1);
        }
    
        return hm;
    }
    

    我可能会忘记一些堕落的案例,但是写这个答案要比提出简单的解决方案花费更长的时间,所以如果有错误,你就是靠自己。数学似乎很有用,所以它可能是正确的。