最大数字序列和问题,买卖股票问题,以及最长公共字串问题

  


最大数字序列和问题

最大数字序列和原理

给定由n个整数(可能为负整数)组成的序列A1,A2,A3,...,An,求该序列的连续子段的和的最大值。当所有整数均为负整数时定义其最大子段和为0

例如   {-4, 11,-2, 13,-7,-3,12} 的最大子段和为22


int MaxSum(int[] array,int n)  
{  
    int b=0;  
    int sum=0;  
    for(int i=1;i<=n;i++)  
    {  
        if(b>0)  
        {  
            b+=array[i];  
        }  
        else  
        {  
            b=array[i];  
        }  
        if(b>sum)  
        {  
            sum=b;  
        }  
    }  
    return sum;  
}  


买卖股票问题:

点击打开链接

1,一次买卖股票受益最大

分析:此题就是选择买入卖出股票的最大收益,对于第i天卖出的最大收益即为第i天的股市价格减去[0,i-1]天内的最小股市价格,当第i天的股市价格比漆面最低股市价格还低,则更新最低股市价格。然后取最大的股市收益,为DP问题。用profit[i]表示第i天的收益,则minBuyPrice = min(minBuyPrice, prices[i]),并且profit[i] = prices[i]-minBuyPrice.   然后取profit中的最大值。

class Solution {
public:
    int maxProfit(vector<int> &prices) {
        int n = prices.size();
        if(n == 0) return 0;
        int maxPro = 0;
        int minBuyPrice = prices[0];
        for(int i = 1; i < n; i++){
            minBuyPrice = min(minBuyPrice, prices[i]);   // 用于记录当前天买进的最小值 minBuyPrice[i+1] = min(minBuyPrice[i], nums[i])
            if(maxPro < (prices[i]- minBuyPrice)){     // 全局最大利益是否小于当天的利益 
                maxPro = prices[i]- minBuyPrice;
            }
        }
        return maxPro;
        
    }
};

2,不限制买卖次数,收益最大问题

此题是上题的变形,买入卖出的次数没有限制,但是第二次买入必须在第一次卖出的时间节点之后,,此时存在一个局部最优,即 2 4 5 3 6 8,此时8-2一定小于5-2+8-3,,因此就有取数组每次递增的收益即为局部最优,然后所有的局部最优加起来就是全局最优

法一(最简洁,干净,利落):

class Solution {
public:
    int maxProfit(vector<int> &a) {
        int profit = 0;
        for (int i = 1; i < a.size(); ++i) {
            if (a[i] > a[i-1]) {
                profit += a[i]-a[i-1];
            }
        }
        return profit;
    }
};


法二:

class Solution {
public:
    int maxProfit(vector<int> &prices) {
        int n = prices.size();
        if(n == 0) return 0;
        int minBuyPrice = prices[0];
        int sumResult = 0;
        /*for(int i = 0; i < n; i++){
            if(i+1 < n && prices[i] >= prices[i+1]){     // 局部最优在于当prices[i] >= prices[i+1] 
                sumResult += prices[i]-minBuyPrice;    //既可用prices[i]-minBuyPrices了找到局部最优了--全部加起来就是全局最优解了
                minBuyPrice = prices[i+1];
            }else{
                if(i+1 == n) sumResult += prices[i]-minBuyPrice;
            }
        }*/
        for(int i = 1; i < n; i++){
            if(prices[i] < prices[i-1]){           // 在i处有一个局部最优,所有的局部最优和就是全局最优
                sumResult += prices[i-1]- minBuyPrice;
                minBuyPrice = prices[i];
            }
        }
        sumResult += prices[n-1]- minBuyPrice;
        return sumResult;
    }
};
3,最多买卖两次股票受益最大问题

此题亦即变形,也就是求交易次数最多为两次。当然有两种方法,第一种暴力,对于每个i,我们求[0,i]与[i,n-1]两次收益,然后求和,遍历i,可以取其中的最大值,需要O(N^2)的时间。第二种方法是动态规划,用两个数组,第一个数组f1[i]用来表示在[0,i]内进行买入卖出的最大收益,用f2[i]表示在[i,n-1]内进行买入卖出的最大收益。然后最大收益即为max(f1[i]+f2[i]),如何求f1[i]和f2[i],,可参考上面的一次买卖股票问题。

class Solution {
public:
    int maxProfit(vector<int> &prices) {
        int n = prices.size();
        if(n <= 1) return 0;
        vector<int> f1(n);  // 表示在[0,i]内进行买入卖出所能获得的最大profit
        vector<int> f2(n);  // 表示在[i, n-1]内进行买入卖出所能获得的最大profit  结果就为max(f1[i]+f2[i])
        
        int minPrice = prices[0];
        
        for(int i = 1; i < n; i++){
            minPrice = min(minPrice, prices[i]);
            f1[i] = max(f1[i-1], prices[i]- minPrice);   
        }
        
        int maxPrice = prices[n-1];
        for(int i = n-2; i >=0; i--){     // 这里要从后往前遍历
            maxPrice = max(maxPrice, prices[i]);
            f2[i] = max(f2[i+1], maxPrice - prices[i]);
        }
        int maxResult = 0;
        for(int i = 0; i < n; i++)
            maxResult = max(maxResult, f1[i]+f2[i]);
        return maxResult;
    }
        
};
4,最多买卖k次股票问题

分析:此题为较难的动态规划问题。首先要第一步就是要转化成动态规划问题, 其次是要写出递归式。我们用local[i][j]表示第i天最多交易j次并且最后一次卖出在第j天所获得的最大利润;global[i][j]用来表示第i天最多交易j次所获得的最大利润。

那么local[i][j]的递归式为


local[i][j] = max(global[i-1][j-1]+ max(diff, 0), local[i-1][j]+diff).


其中diff = prices[i] - prices[i-1];  global[i-1][j-1]表示第i-1天最多进行j-1次交易获得的最大利润,如果diff大于0,那么那么就加上今天获得利润,diff<0,那么最后一次就可以看做是当天买入并卖出。local[i-1][j]表示第i-1天最多进行j次交易获得的利润,加上diff就等于local[i][j]。 取两者最大值。

global[i][j]的递归式为:


global[i][j] = max(global[i-1][j], local[i][j]); 


也就是取第i-1天最多进行j次交易和第i天交易并且最多交易j次且最后一次交易在第i天的利润的最大值。


class Solution {
public:

    int maxProfit(int k, vector<int>& prices) {
        int n = prices.size();
        if(k >= n/2) return maxProfit2(prices);
        vector<int> lp(k+1);
        vector<int> gp(k+1);
        for(int i = 1; i < n; i++){
            int diff = prices[i]- prices[i-1];
            for(int j = k; j>0; j--){
                lp[j] = max(gp[j-1]+max(diff, 0), lp[j]+diff);
                gp[j] = max(gp[j], lp[j]);
            }
        }
        return gp[k];
        
    }
    int maxProfit2(vector<int> &prices){
        int ans = 0;
        for(int i = 1; i < prices.size(); i++){
            ans += max(prices[i]-prices[i-1], 0);
        }
        return ans;
    }
};




最长公共子串问题

点击打开链接        点击打开链接

动态规划:如果X[i]==Y[j],那么dp[i][j]=dp[i-1][j-1]+1;

如果X[i]!=Y[j],那么dp[i][j]=0;



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值