一道小面试算法题的思路

一道小算法题的思路

有这么一道小面试算法题:给定一个长度为 n 的整数数组,下标为 i 的元素表示第 i 天某个股票的价格,每次最多持有一股,每次买卖最多一股,在最多只买卖一次的情况下(先买后卖,不考虑融券等复杂形式),最大的收益是多少。

先考察一下可能的数据:

 0   1   2   3   4   5   6   7
12   9   6  10   8  22  20  15

由于是先买后卖,从数据上看,是在 2 处买入,5 处卖出时,得到收益为 16 最大。

而在股票一直下跌的情况下,不买不卖,得到的收益为 0 最大。

  1. o(n^2) 直观算法

    最简单的思路,就是从前向后逐个计算收益,求最大收益,如下:

     price[n]
     max_profit = 0
     for i = 0...n-2:
         for j = i+1...n-1:
             profit = price[j] - price[i]
             if profit > max_profit:
                 max_profit = profit
    

    这个算法的复杂度为 o(n^2) ,能不能继续优化?

  2. o(n) 算法

    用归纳法分析一下,在第 n-1 天时,最大收益为 max_profit ,其中最小的价格为 min_price,那么第 n 天时,最大的收益计算为:

     if price[n] - min_price > max_profit:
         max_profit = price[n] - min_price
    

    因此,可把算法改为:

     price[n]
     max_profit = 0
     min_price = price[0]
     for i = 1...n-1:
         profit = price[i] - min_price
         if profit > max_profit:
             max_profit = profit
         if min_price > price[i]:
             min_price = price[i]
    

    变化为 o(n) 复杂度。

  3. 推广变化

    现在,考虑更加复杂的形式,先来个允许不限次数的买卖,那么,在每一个递增的子区间,都能得到收益,总收益为各个收益的和:

     price[n]
     sum_profit = 0
     for i = 1...n-1:
         profite = price[i] - price[i-1]
         if profite > 0:
             sum_profit += profit
    

    再复杂一点,允许进行融券形式(即允许从券商借出后先卖后买),同样限制最多持有或融入 1 股,在结束前使得手上股票数为 0 。这种规则下,股票价格升降都会得到收益,总收益为:

     price[n]
     sum_profit = 0
     for i = 1...n-1:
         profite = price[i] - price[i-1]
         if profite < 0:
             sum_profite += -profite
         else:
             sum_profite += profite
    

    在此基础上,还可以放开一些限制条件,如不限制持有的数量等等。更进一步,可设定一个收益目标,符合收益目标的买卖组合,这样就更加现实意义有意思了。

posted @ 2018-03-21 16:51  drop *  阅读(172)  评论(0编辑  收藏  举报