Add to List 121. Best Time to Buy and Sell Stock,我的解题思路

来源:互联网 发布:陕西大数据集团 编辑:程序博客网 时间:2024/05/22 06:30

leetcode上的一道题,说一下我的解题思路,以及后来的赶紧思路,以下是原题:

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

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.

Example 1:

Input: [7, 1, 5, 3, 6, 4]
Output: 5

max. difference = 6-1 = 5 (not 7-1 = 6, as selling price needs to be larger than buying price)

Example 2:
Input: [7, 6, 4, 3, 1]
Output: 0

In this case, no transaction is done, i.e. max profit = 0.

这个题的本质,就是找一对数,使在数组相对右边的数减去相对左边的数。比如我找了一对数,6,1, 1在数组中的位置比6靠右,就用1减6,因为是负数,所以就等于0。

第一次的解题思路:

第一次是暴力解法,我在想既然是找出差值最大的一对数,那我算出来所有对的差值,然后从这些差值中找出最大值不就行了吗?
代码如下

class Solution {public:    int maxProfit(vector<int>& prices) {       // cout << prices.size() << endl;        if (!prices.size()) return 0;        if (prices.size() == 1) return 0;        vector<int> results;        for (int day_index = prices.size() - 1; day_index >= 0; day_index--)        {            for (int days_left = prices.size() - 1; days_left > day_index; days_left--)            {                if ((prices[days_left] - prices[day_index]) > 0 )                results.push_back(prices[days_left] - prices[day_index]);            }        }        if (!results.size()) return 0;        int max = *std::max_element(results.begin(), results.end());        return (max > 0)? max : 0;    }};

如图,用了两次for循环,运行结果是565 ms。。。只击败了百分之1.78的用户。。。

第二次的解题思路:

很明显,时间都浪费在了两层for循环上了,因此,是不是可以优化一下,不用两层for循环呢?那就要看看哪些计算是多余的。

我刚开始是从三个元素的数组开始推导的。两个元素的数组就不用推了,太简单了。
三个元素的数组,按照大小排列顺序的话,总共有6种排列顺序:

小 中 大
小 大 中
中 小 大
中 大 小
大 小 中
大 中 小

大中小分别代表数组中最大的数,中间的数和最小的数。

我们先来考虑最简单的两种情况,即 小中大,大中小。 这种情况下,我们不需要计算 大-小和小-大这对数了,只需要计算 中-小,大-小或者 中-大,小-中,也就是说,我们在这种情况下,只需要计算相邻元素的差值就行了。

再来考虑小大中, 同样的,最大差值也只可能是 大-小这对数,所以,同样的,我们对于这种情况也不需要计算中减大,只需要计算相邻元素的差值。

把这六种情况分析完以后,都可以得到一个结论,对于3个元素的数组,我们只需要计算相邻元素差值就行了。

那么对于四个元素的数组呢?四个元素的数组情况太复杂了,一个一个分析太难,我试图把四个元素的数组看成两部分,一部分是三个元素的数组,第二部分是剩下的最右边的第四个元素,然后找到这两个部分的联系。
比如:

小, 大, 中, X

X代表第四个元素。前三个元素中的最大差值我们已经知道了,假设为a。新添加了一个元素X以后,所能出现的最大差值,就是 X-小 。 如果X-小 > a,则新的最大差值就是X-小。如果X-小 <= a,则添加新元素后的四元数组的最大差值不变。也就是说,对于新数组来说,X对于最大差值来说并没有任何贡献。

因此我们找到了一个新的解题思路:
对于n个元素的数组,我们可以看成n-1个元素和第n个元素的结合,如果我们知道n-1个元素数组中的最小值和最大差值,那么n元数组中的最大差值也可以算出来。

以下是代码:

class Solution {public:    int maxProfit(vector<int>& prices) {       // cout << prices.size() << endl;       if(prices.size() == 1 || prices.size() == 0) return 0;       int min_num = INT_MAX ;       int final_max_profit = 0;       for (int day_index = 0; day_index < prices.size() - 1; day_index++)       {           if(prices[day_index] < min_num) min_num = prices[day_index];           int cur_max_profit = prices[day_index + 1] - min_num;           if(cur_max_profit > final_max_profit) final_max_profit = cur_max_profit;       }       return final_max_profit;    }};

运行结果是6ms,打败了百分之33的用户。其实我看了前百分之1的用户写的答案,思路和我的差不多,运行时间也是6ms,可能一些小细节有优化吧。

可以看到,第二次的解题思路比第一次少了很多,差不多是第一次的百分之一了。其实这个方法还能被优化,就是根据X和X左边的元素进行比较,分成两种情况进行计算,我试了以后,运行时间反而增加了,变成了十几ms,可能是因为比较两个元素的大小是一个很费时的操作吧,所以我就不介绍这种优化了。

原创粉丝点击