【问题标题】:Divide and conquer algorithm in linear complexity? [duplicate]线性复杂度的分治算法? [复制]
【发布时间】:2015-04-24 02:39:28
【问题描述】:

我们有一组代表价格随时间变化的数字。例如,我们有 [10, 4, 6, 8, 2, 5, 3, 9, 1]。我们想知道什么时候是买卖以最大化利润的最佳时机。在这种情况下,我们将在时间[4] = 2 买入并在时间[7] = 9 卖出,从而获得 9 - 2 = 7 的利润。

在数学上,我们正在寻找 a 和 b,其中 a

使用分治法制作复杂度为 O(nlogn) 的算法有些微不足道。我一直在寻找一种最坏情况 O(n) 的算法,但没有成功。任何帮助将不胜感激。

【问题讨论】:

    标签: algorithm time-complexity divide-and-conquer


    【解决方案1】:

    这里不需要分而治之。从最旧的价格到最新的价格遍历数组,并在每一步将当前价格与目前找到的最低价格进行比较。

    【讨论】:

    • 赞成比我的简单得多的答案:-)
    【解决方案2】:

    如果我们作为第一步预先计算一个向量,该向量指定索引 i 的每个范围 (0, i-1) 的最低价格,然后计算我们在索引 i 处卖出时可以达到的最高价格,我们可以在 O(n) 时间内轻松计算:

    代码:

    #include <iostream>
    #include <algorithm>
    #include <limits>
    #include <vector>
    using namespace std;
    
    int main() {
        vector<int> prices{10, 4, 6, 8, 2, 5, 3, 9, 1};
        // sell at time [i] requires buy at minimum in range [0,i-1]
        // create vector of index at minimum for each range
        int currentMinimumIndex = 0;
        vector<int> minimums{0};
        for(size_t i = 1; i < prices.size(); ++i)
        {
            if (prices[i] < prices[currentMinimumIndex])
            {
                minimums.emplace_back(i);
                currentMinimumIndex = i;
            }
            else
                minimums.emplace_back(currentMinimumIndex);
        } // O(n)
    
        // at this point we have a lookup table for minimum in every range
    
        // attempt to maximize amount we can get if we sell at time i buy buying at minimum for (0,i-1)
        vector<int> maxSales{std::numeric_limits<int>::min()};
        for(size_t i=1;i<prices.size();++i)
        {
            maxSales.emplace_back(prices[i] - prices[minimums[i]]);
        } // O(n)
    
        // find maximum element
        auto maxSum = std::max_element(std::begin(maxSales), std::end(maxSales)); // O(n)
        auto sellAt = std::distance(std::begin(maxSales), maxSum);
        auto buyAt = minimums[sellAt];
        std::cout << "Maximum profit is " << *maxSum << std::endl;
        std::cout << "If we buy at index " << buyAt << " (price: " << prices[buyAt] << ")"
        << " and sell at " << sellAt << " (price: " << prices[sellAt] << ")" << std::endl;
    
        return 0;
    }
    

    输出:

    最大利润为 7 如果我们以指数 4(价格:2)买入并以 7(价格:9)卖出

    Live Example

    编辑:这是一种动态编程式的方法,我现在意识到它有点矫枉过正。如果我们做什么hugomg said 然后我们将简单地从左到右迭代,存储到目前为止找到的最小值。在每个新索引 i 处,我们执行减法以查看是否有新的最大价格。时间线性,空间常数。

    【讨论】:

      【解决方案3】:

      [10, 4, 6, 8, 2, 5, 3, 9, 1]。

      将上面的列表转换为 O(n) 中的梯度。 [-6,2,2,-6,3,-2,6,-8]

      应用 Kadane 算法求最大子数组 O(n): http://en.wikipedia.org/wiki/Maximum_subarray_problem

      ^修改存储起始位置和结束位置。

      使用 kadane 算法中的起始位置来查找原始数组的起始和结束位置。

      【讨论】:

      • 这是 Kadane 的算法。
      猜你喜欢
      • 2019-10-05
      • 2013-10-12
      • 2023-03-03
      • 1970-01-01
      • 2016-02-06
      • 2021-06-22
      • 2018-08-24
      • 1970-01-01
      • 2021-11-30
      相关资源
      最近更新 更多