• leetcode-188 买卖股票4


    题目

        给定一个数组表示股票每天的价格,最多交易k次,且手上最多只能拥有一支股票(即只能先卖出手上现有的股票再去购买新的股票),求最大的收益。 
        题目链接:买卖股票4 
        开始思路不清楚,参考了http://blog.csdn.net/dr_unknown/article/details/51939121 的解法。 
    使用动态规划,先找清状态,题目中有两个主要变量天数,和交易次数,以及所要求的结果:最大的收益。那么可以构造状态dp[i][j],表示前i天最多交易j次获得的最大收益。 
        有了状态dp,可以找到递推公式:dp[i][j] = max{dp[i-1][j], dp[i-1][j-1] + prices[i] - prices[i-1]}:前i天进行j次的最大收益,等于前i-1天进行完最多j次交易的收益A和前i-1天进行完j-1次交易,且第i天进行最后一次交易的收益B的最大值。 
        但是这样有个问题,对于第二种情况,如果dp[i-1][j-1]中第j-1次交易是在第i-1天进行了卖出,那么 dp[i-1][j-1] + prices[i] - prices[i-1] 就相当于第j-1次交易是在第i天进行了卖出,最终相当于i天最多只进行了j-1次交易。 
        于是,需要细化状态,考虑使用状态 local[i][j]表示前i天最多进行j次交易,且最后一次卖出交易是在第i天完成,所获得的最大收益;global[i][j]表示前i天最多进行j次交易所获得的最大收益。 
    于是有递归公式: 
    local[i][j] = max{global[i-1][j-1] + max(prices[i] - prices[i-1], 0), local[i-1][j] + prices[i] - prices[i-1]} 
    global[i][j] = max{local[i][j], global[i-1][j]}
     
        进一步的,状态第一维i只和i-1有关,可以进行空间压缩,将二维数组变成一维,于是有递推公式: 
    local[j] = max{global[j-1] + max(prices[i] - prices[i-1], 0), local[j] + prices[i] - prices[i-1]} 
    global[j] = max{local[j], global[j]}
     
    但是需要注意j需要从高到低遍历,因为第i天交易j次的最优解依赖于第i-1天交易j-1次的最优解。 
        进行状态压缩时,数组的遍历方向很容易搞混,这是可以使用滚动数组,滚动数组一方面可以压缩空间,另一方面也不需要太过考虑数组的遍历方向。 
    local[new_scroll][j] = max(global[old_scroll][j-1] + max(diff, 0), local[old_scroll][j] + diff); 
    global[new_scroll][j] = max(local[new_scroll][j], global[old_scroll][j]);

    实现

    class Solution {
    public:
    	int maxProfit(int k, vector<int> &prices) {
    	    int n = prices.size();
    	    if(n <= 1)
    	        return 0;
    	    if(k >= n)
    	        return maxProfit2(prices);
    	    for(int i = 0; i < 2; i ++){
    	        local[i].assign(k + 1, 0);
    	        global[i].assign(k + 1, 0);
    	    }
    	    int old_scroll = 0, new_scroll;
    	    for(int i = 1; i < n; i ++){
    	        int diff = prices[i] - prices[i-1];
    	        new_scroll = 1 - old_scroll;
    	        for(int j = 1; j <= k; j ++){
    	            local[new_scroll][j] = max(global[old_scroll][j-1] + max(diff, 0), local[old_scroll][j] + diff);
    	            global[new_scroll][j] = max(local[new_scroll][j], global[old_scroll][j]); //注意这里 local 为new_scroll
    	        }
    	        old_scroll = new_scroll;
    	    }
    	    return global[new_scroll][k];
    	}
    	int maxProfit2(vector<int>& prices){
    	    int result = 0;
    	    int n = prices.size();
    	    for(int i = 1; i < n; i ++){
    	        if(prices[i] > prices[i-1])
    	            result += (prices[i] - prices[i-1]);
    	    }
    	    return result;
    	}
    private:
        vector<int> local[2];
        vector<int> global[2];
    };
    
  • 相关阅读:
    使用C#编写SqlHelper类
    编译器perspective oo 对象模型(1) 之 初窥c++对象模型
    浅谈 编译器 & 自然语言处理
    基于c#的角色扮演游戏设计与实现
    开源的EtherCAT Master简介
    如何在Windows中编译Linux Unix的代码(采用cygwin)?
    sql拼语句例子
    IOC介绍-手写一个简单的IOC
    protocalBuffer_java版详解(转thanks)
    ProtocalBuffer_数据结构(转thanks)
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/5765565.html
Copyright © 2020-2023  润新知