`

Algorithm之动态规划之最佳买股票时机

 
阅读更多
动态规划(DP: Dynamic Programming)

一、基本思想与策略

基本思想与分治法类似,也是将待求解的问题
    - 分解为若干个子问题(阶段)
    - 按顺序求解子问题,
    - 前一个(或前有限个,一般不超过三个)子问题的解,为后一子问题的求解提供了有用的信息。
    - 在求解子问题时,需要求得各种可能的解。这些解是累计关系,是当前子问题的最终解。
    - 依次解决各子问题,最后一个子问题的解就是初始问题的解。

动态规划的子问题是可以用来判定结果的最短子问题,或是前后两个,或是前后三个,总之是有限个。
由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,
可将子问题及其输出保存在一个二维数组中。

与分治法最大的差别是:
适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的,
即下一个子问题的求解是建立在上一个(几个)子问题的解的基础上进行求解。


二、动态规划过程

每次决策需要依赖于以前的状态,随即又产生新的状态。
每步都选择最优状态,但是其它状态也需要保留,以便为后面的决策提供依据。
一个决策序列就是在变化的状态中产生出来的,所以这种多阶段最优化决策解决问题的过程就称为动态规划。


三、例子:最佳买股票时机(三种情况)

1、Best Time to Buy and Sell Stock -- LeetCode
http://blog.csdn.net/linhuanmars/article/details/23162793

求进行一次交易能得到的最大利润。
用“局部最优和全局最优解法”。
思路是维护两个变量,一个是到目前为止最好的交易,另一个是今天买明天卖的最佳交易。
这样一次扫描就可以得到结果,时间复杂度是O(n)。而空间只需要两个变量,即O(1)。

public int maxProfit(int[] prices) {  
    if(prices==null || prices.length==0) return 0;  
    int local = 0;  
    int global = 0;  
    for(int i=0;i<prices.length-1;i++){
        local = Math.max(local+prices[i+1]-prices[i],0);  
        global = Math.max(local, global);  
    }  
    return global;  
}


这种题目的解法非常经典,不过是比较简单的动态规划。


2、Best Time to Buy and Sell Stock II -- LeetCode
http://blog.csdn.net/linhuanmars/article/details/23164149

可以交易任意次数。
只要对每次两天差价大于0的都进行交易,就可以得到最大利润。
因此算法其实就是累加所有大于0的差价既可以了。


public int maxProfit(int[] prices) {  
    if(prices == null || prices.length==0) return 0;
    int res = 0;  
    for(int i=0;i<prices.length-1;i++){    
        int diff = prices[i+1]-prices[i];  
        if(diff>0)  
            res += diff;  
    }  
    return res;  
}  




3、Best Time to Buy and Sell Stock III -- LeetCode
http://blog.csdn.net/linhuanmars/article/details/23236995

最多可以进行K次交易。
还是使用“局部最优和全局最优解法”。
对于天数需要一次扫描,而每次要对交易次数进行递推式求解,所以时间复杂度是O(n*k)。

下面是 K = 2 的情况:
public int maxProfit(int[] prices){
    if(prices==null || prices.length==0) return 0;
    int[] local = new int[3];
    int[] global = new int[3];
    for(int i=0;i<prices.length-1;i++){
        int diff = prices[i+1]-prices[i];
        for(int j=2;j>=1;j--){
            local[j] = Math.max(global[j-1]+(diff>0?diff:0), local[j]+diff);
            global[j] = Math.max(local[j],global[j]);
        }
    }
    return global[2];
}


完善版本:

/*
* j -- max # of transactions; i --- # of days;
*  local[i][j] -- profit achieved when selling at last day;
*  global[i][j] --- profit achieved at all situations;
*  transition equation:
*       local[i][j] =  max(local[i - 1][j], global[i - 1][j - 1]) + diff;
*      (merge with previous transactions or NOT)
*      global[i][j] = max(local[i][j], global[i - 1][j]);
*/
public class SolutionIV {
    public int maxProfit(int k, int[] prices) {
            int N = prices.length;
            if (k >= N)
                    return simpleMaxProfit(prices);
        int[] local = new int[k + 1], global = new int[k + 1];
        int[] prevLocal = new int[k + 1], prevGlobal = new int[k + 1];
        for (int i = 1; i < N; ++i) {
                prevLocal = local; prevGlobal = global;
                local = new int[k + 1]; global = new int[k + 1];
                int diff = prices[i] - prices[i - 1];
                for (int j = 1; j <= k; ++j) {
                        local[j] = Math.max(prevGlobal[j - 1], prevLocal[j]) + diff;
                        global[j] = Math.max(local[j], prevGlobal[j]);
                }
        }
        return global[k];
    }
    int simpleMaxProfit(int[] prices) {
            int N = prices.length;
            if (N <= 1)
                    return 0;
            int sum = 0;
            for (int i = 1; i < N; i++) {
                    int diff = prices[i] - prices[i - 1];
                    if (diff > 0)
                            sum += diff;
            }
            return sum;
    }
    public static void main(String[] args) {
        SolutionIV sol = new SolutionIV();
        int[] nums = {4, 6, 1, 1, 4, 2, 5};
        System.out.println(sol.maxProfit(2, nums));
    }
}






四、例子:买股票的最佳时机



package solution;

import org.junit.Test;

public class BestTimetoBuyAndSellStockwithCooldown {
    
    
// 最佳买股票时间有多种玩法和限制。
// 本例只举其一种。
/*
LeetCode : 
https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown
309. Best Time to Buy and Sell Stock with Cooldown
 * 
Say you have an array for which the ith element is the price of a given stock 
on day i.

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) with the following restrictions:

    - You may not engage in multiple transactions at the same time 
      (ie, you must sell the stock before you buy again).
      
    - After you sell your stock, you cannot buy stock on next day. 
      (ie, cooldown 1 day)
    
Example:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

 */

    @Test
    public void testBuyandSell(){
        int[] prices = new int[] {1, 2, 7, 0, 2, 7, 100};
        System.out.println(maxProfit(prices));
    }
    
/*
 * 分析:    
 *------------------------------------------------------------------------------
 *
 *     对于每天来讲:只会出现在这三种状态之中:buy, sell, rest
 *        
 * buy[i] means before day i what is the maxProfit for any sequence end with buy.
 *        计算今天状态为 buy 时的最好收益:
 *        buy[i]  = max(rest[i-1]-price, buy[i-1])
 *        买入的状态 =  max(昨天冻结今天买,昨天已买入) 
 *
 * sell[i] means before day i what is the maxProfit for any sequence end with sell.
 *        记算今天状态为 sell 时的最好收益:
 *        sell[i] = max(buy[i-1]+price, sell[i-1])
 *        卖出的状态 = max(昨天为买今天卖出,昨天已卖出)
 *        
 * rest[i] means before day i what is the maxProfit for any sequence end with rest.
 *        记算今天状态为 rest 时的最好收益:
 *        rest[i] = sell[i-1]
 * 
 * -------------------------------------------------------------------------------------
   
    The series of problems are typical dp. The key for dp is to find the variables 
    to represent the states and deduce the transition function.

    Of course one may come up with a O(1) space solution directly, 
    but I think it is better to be generous when you think and be greedy when you 
    implement.
    
    The natural states for this problem is the 3 possible transactions : 
    buy, sell, rest. 
    
    Here rest means no transaction on that day (aka cooldown).    
    Then the transaction sequences can end with any of these three states.    
    For each of them we make an array, buy[n], sell[n] and rest[n].
    
        buy[i] 
        means before day i what is the maxProfit for any sequence end with buy.
    
        sell[i] 
        means before day i what is the maxProfit for any sequence end with sell.
    
        rest[i] 
        means before day i what is the maxProfit for any sequence end with rest.
    
    Then we want to deduce the transition functions for buy sell and rest. 
    By definition we have:
    
    buy[i]  = max(rest[i-1]-price, buy[i-1]) 
    sell[i] = max(buy[i-1]+price, sell[i-1])
    rest[i] = max(sell[i-1], buy[i-1], rest[i-1])
    
    Where price is the price of day i. All of these are very straightforward. 
    They simply represents :
    
    (1) We have to `rest` before we `buy` and 
    (2) we have to `buy` before we `sell`
    One tricky point is how do you make sure you sell before you buy, since
    from the equations it seems that [buy, rest, buy] is entirely possible.
    
    Well, the answer lies within the fact that buy[i] <= rest[i] which means 
    rest[i] = max(sell[i-1], rest[i-1]). That made sure [buy, rest, buy] is 
    never occurred.
    
    A further observation is that and rest[i] <= sell[i] is also true 
    therefore:
    
    rest[i] = sell[i-1]
    
    Substitute this in to buy[i] we now have 2 functions instead of 3:
    
    buy[i] = max(sell[i-2]-price, buy[i-1])
    sell[i] = max(buy[i-1]+price, sell[i-1])
    
    This is better than 3, but we can do even better
    
    Since states of day i relies only on i-1 and i-2 we can reduce 
    the O(n) space to O(1). 
  
     */

    private int maxProfit(int[] prices) {
        int sell = 0, prev_sell = 0, buy = Integer.MIN_VALUE, prev_buy;
        for (int price : prices) {
            prev_buy = buy;
            buy = Math.max(prev_sell - price, prev_buy);
            prev_sell = sell;
            sell = Math.max(prev_buy + price, prev_sell);
        }
        return sell;
    }
    

}










引用:
https://zh.wikipedia.org/zh-tw/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92

http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741374.html

https://leetcode.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/

五大常用算法之二:动态规划算法
http://www.cnblogs.com/steven_oyj/archive/2010/05/22/1741374.html












-



分享到:
评论

相关推荐

    python买卖股票的最佳时机(基于贪心/蛮力算法)

    在Python编程中,买卖股票的最佳时机是一个经典的算法问题,它涉及到贪心算法和蛮力算法的应用。本问题的目的是在给定的股票价格数组中找到最大的利润,允许进行多次交易,但每次交易完成后,必须先卖出股票才能再次...

    C++动态规划源码.zip

    8. **股票交易**:如买卖股票的最佳时机,找到可以获得最大利润的交易策略。 9. **动态规划状态转移方程**:如Kadane's Algorithm,用于找出数组中的最大子数组和。 10. **图的着色问题**:在有限的颜色集中给图的...

    动态规划算法

    9. **股票交易问题**:如买卖股票获取最大利润,可以通过动态规划找到最佳买入和卖出时机。 10. **N皇后问题**:在n×n的棋盘上放置n个皇后,要求任何两个皇后不能在同一行、同一列或对角线上,求解可行的放置方案...

    股票买卖最佳时机leetcode-algorithm-practice:算法实践

    股票买卖最佳时机leetcode 算法实践 几个算法练习来升级。 来自不同的站点/测试。 数组游戏:增加除一个之外的所有数组元素,直到它们相等。 彩票优惠券:找到在最大数量的可能中奖者中选择最大中奖组合的方法数。 ...

    动态规划的一些资料--挺详细的

    8. 股票交易问题:如买卖股票的最佳时机,寻找最多可以赚取多少利润。 动态规划的五大要素包括: 1. 状态:定义问题的当前阶段,通常是问题的某个属性组合。 2. 决策:在当前状态下可采取的动作或选择。 3. 状态...

    股票买卖最佳时机leetcode-Algorithm-Trading-using-Deep-Q-Reinforcement-Learning:

    股票买卖最佳时机leetcode 算法交易使用深度Q强化学习 介绍 股票交易策略在投资中起着至关重要的作用。 然而,在复杂多变的股票市场中设计盈利策略具有挑战性。 在这个项目中,我们提出了一种策略,该策略采用深度...

    股票买卖最佳时机leetcode-Stockvalue:买入股票的最佳时间和价格以及卖出股票的最佳时间和价格,以获得最大利润评估过去一天的价值

    股票买卖最佳时机问题是一个经典的计算机科学中的动态规划问题,它在LeetCode等在线编程平台上非常常见,用于测试程序员解决实际问题的能力。这个问题涉及到对股票价格序列的分析,目的是找到一个策略,使得在允许的...

    股票买卖最佳时机leetcode-purchasing_shares_demo:演示在cloudquant环境中购买股票的不同方式

    股票买卖最佳时机leetcode share_ordering_demo 该存储库包含演示如何在 cloudquant 回测中买卖股票的教程。 没有单一的“正确方法”可以做到这些。 你必须仔细考虑你的算法,它如何决定何时买入和卖出,你想要实现...

    leetcode股票算法-geek-algorithm-leetcode:极客算法leetcode

    买卖股票的最佳时机 Meidum Greedy,DP 股票 122 买卖股票的最佳时机 II Meidum Greedy,DP 股票 123 买卖股票的最佳时机 III Hard Greedy,DP 股票 126 单词接龙 II Hard DFS,BFS,Graph DFS+BFS双向搜索待完善 127 ...

    genetic-algorithm-trading:用于进化遗传算法以在股票市场交易的 ruby​​ 模拟

    在股票交易中,这些解可能代表不同的投资策略,如买入、卖出的时机,股票的选择,甚至包括资金管理等方面。 在Ruby中实现遗传算法,首先要理解Ruby的基础语法和特性,如面向对象编程、动态类型等,以便构建灵活且...

    leetcode2-Algorithm-swift:记录一下,算法学习

    买卖股票的最佳时机 122. 买卖股票的最佳时机 II 141. 环形链表 142. 环形链表 II 146. LRU缓存机制 148. 排序链表 155. 最小栈 160. 相交链表 176. 第二高的薪水 203. 移除链表元素 206、反转链表 215. 数组中的第K...

    基于GA的股票数据挖掘java源码

    在股票数据分析中,GA可以用来寻找最佳的投资策略,如买卖时机的选择。其基本步骤包括初始化种群、适应度评价、选择、交叉和变异等。 二、Java源码解析 “StockMiner1.0.4”这个文件名可能代表了该软件的版本号,...

    leetcode数组下标大于间距-my-algorithm:我的算法

    leetcode数组下标大于间距 my-algorithm 高频题目,必刷 别人写的: ...21.买卖股票的最佳时机 122.买卖股票的最佳时机 II 123.买卖股票的最佳时机 III 重建二叉树 路径总和 路径总和 II 首个共同祖先 二

    javalruleetcode-algorithm-coding:算法编码

    java lru leetcode lishinho's algorithm-coding lishinho算法模板,用于积累各基础面试算法逻辑,目前以JAVA语言刷 现阶段也已经有了 学习建议:数据结构 ...买卖股票的最佳时机 (动态规划) leetcode

    lrucacheleetcode-DataStructureAndAlgorithm:小算法问题

    有冷却时间买卖股票的最佳时机 最小堆栈 珠宝和石头 合并两个二叉树 反向链表 有效字谜 查找字符串中的所有字谜 字符串中的第一个唯一字符 爬楼梯的最低成本 二叉搜索树的最低公共祖先 二叉树的最低公共祖先 链表...

    <算法分析与设计>试卷

    3. 股票买卖问题:如买卖股票的最佳时机、买卖股票的最佳时机II、买卖股票的最佳时机III等,这些都是动态规划在实际问题中的应用。 三、递归与分治 1. 递归算法:如斐波那契数列、汉诺塔、八皇后问题等,理解递归的...

    leetcode题库-Algorithm:leetcode/lintcode上的算法练习

    leetcode题库 Algorithm leetcode/lintcode上的算法题 About 这个仓库最初的想法是把lintcode/lintocde上面的算法题目整理一下,因为很多题目太多了显得太乱了,就不继续在GitHub上面写了...买卖股票的最佳时机1,2,3

    leetcode跳跃-leetcode_Algorithm_problem:Leetcode算法题

    121.买卖股票的最佳时机 122.买卖股票的最佳时机II 123.买卖股票的最佳时机III 125.验证回文串 126.单词接龙 II 127.单词接龙 130.被围绕的区域 14.最长公共前缀 141.环形链表 142.环形链表 II 144.二叉树的前序遍历...

    LeetCode,《剑指offer》中的算法题的题目和解法以及常见算法的实现

    Best Time to Buy and Sell Stock"股票买卖问题,可以利用动态规划找到最佳买卖时机。 5. 排序与查找:排序算法如快速排序、归并排序,查找算法如二分查找,都在实际面试中经常出现。例如,"148. Sort List"要求对...

    数据结构和算法试题-总共1000多页带目录

    - 求解最优值的问题,例如:最后一块石头的重量II、买卖股票的最佳时机、礼物的最大价值等。 - 使用动态规划结合其他算法解决问题,如动态规划结合贪心算法解决买卖股票问题、结合双指针解决买卖股票问题、结合中心...

Global site tag (gtag.js) - Google Analytics