leetcode 买卖股票问题 1 2

1、121. 买卖股票的最佳时机

  给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
注意:你不能在买入股票前卖出股票。
两种方法:动规和差分

1.1 动规

 思路:状态转移方程
d p [ i ] = m a x ( d p [ i − 1 ] , p r i c e s [ i ] − m i n p r i c e [ i ] ) dp[i]=max(dp[i-1],prices[i]-minprice[i]) dp[i]=max(dp[i1],prices[i]minprice[i])
  dp[i]表示前i天卖出的最大利润,=max(前i-1天的最大利润,第i天的价格-前i-1天的最低价格)
  动态规划就是选和不选的问题,选第i天卖出的话就是max的第二种情况,不选就是max的第一种情况
  所以还需要一个数组记录前i天的最低价格。 v e c t o r < i n t > m i n p r i c e ( n , 0 ) vector<int> minprice(n,0) vector<int>minprice(n,0)
m i n p r i c e [ i ] = m i n ( m i n [ i − 1 ] , p r i c e s [ i ] ) minprice[i]=min(min[i-1],prices[i]) minprice[i]=min(min[i1],prices[i])
前i天的最低价格=min(前i-1天的最低价格,第i天的价格)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
           int n=prices.size();
           if(n<1)
           return 0;
           vector<int> dp(n,0);
           vector<int> minprice(n,0);
           minprice[0]=prices[0];
           for(int i=1; i<n; i++)
           {
               minprice[i]=min(minprice[i-1],prices[i]);
                dp[i]=max(dp[i-1],prices[i]-minprice[i]);
           }
           return dp[n-1];
    }
};

 当然,我们也可以优化时间复杂度

class Solution {
public:
    int maxProfit(vector<int>& prices) {
           int n=prices.size();
           if(n<1)
           return 0;
           int dp=0;
           int minprice=prices[0];//寻找到当前天的最低价格
           for(int i=1; i<n; i++)
           {
               minprice=min(minprice,prices[i]);
                dp=max(dp,prices[i]-minprice);
           }
           return dp;
    }
};

1.2 差分

 思路:对于一组数据 [ 7 , 1 , 5 , 3 , 6 , 4 ] [7 , 1 , 5 ,3 , 6 , 4 ] [7,1,5,3,6,4],我们求出差分数组为d= [ − 6 , 4 , − 2 , 3 , − 2 ] [-6 , 4, -2 , 3, -2 ] [6,4,2,3,2], d [ i ] = p r i c e s [ i + 1 ] − p r i c e s [ i ] d[i]=prices[i+1]-prices[i] d[i]=prices[i+1]prices[i]
在这里插入图片描述
直观的,在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = p r i c e s [ 4 ] − p r i c e s [ 1 ] = 6 − 1 = 5 =prices[4]-prices[1]= 6-1 = 5 =prices[4]prices[1]=61=5
其实我们发现就是求差分数组的最大子段和, d [ 3 ] + d [ 2 ] + d [ 1 ] = 4 + ( − 2 ) + 3 = 5 d[3]+d[2]+d[1]=4+(-2)+3=5 d[3]+d[2]+d[1]=4+(2)+3=5
这是因为 p r i c e s [ 4 ] − p r i c e s [ 1 ] = p r i c e s [ 4 ] − p r i c e s [ 3 ] + p r i c e s [ 3 ] − p r i c e s [ 2 ] + p r i c e s [ 2 ] − p r i c e s [ 1 ] = d [ 3 ] + d [ 2 ] + d [ 1 ] prices[4]-prices[1]\\ =prices[4]-prices[3]+prices[3]-prices[2]+prices[2]-prices[1]\\ =d[3]+d[2]+d[1] prices[4]prices[1]=prices[4]prices[3]+prices[3]prices[2]+prices[2]prices[1]=d[3]+d[2]+d[1]
所以,我们将求问题转换为求最大字段和的问题,而求数组的最大字段和在我们之前的博客已经提过。状态转移方程为
d p [ i ] = m a x ( d p [ i − 1 ] + n u m [ i ] , n u m [ i ] ) dp[i]=max(dp[i-1]+num[i],num[i]) dp[i]=max(dp[i1]+num[i],num[i])
d p [ i ] dp[i] dp[i]代表着以i结尾的数组的最大子段和,最后我们再进行一次for 循环,找出dp数组中的最大值。

class Solution {
public:
int maxSubArray(vector<int>& nums) {
    //传入差分数组,求其最大子段和
        int dp,predp=nums[0];
        int Maxprice=nums[0];
        for(int i=1;i<nums.size();i++)
        {
            dp=max(nums[i],predp+nums[i]);
              Maxprice=max(Maxprice,dp);
              predp=dp;
        }
        return Maxprice;
    }
    int maxProfit(vector<int>& prices) {
        /*
        买卖股票也可以采用差分
        将其转换为差分数组求其最大子段和就是最大利润
        */
        if(prices.size()==0||prices.size()==1)
        return 0;
        vector<int>b(prices.size()-1,0);
        for(int i=0;i<prices.size()-1;i++)
        {
            b[i]=prices[i+1]-prices[i];
        }
        int n=maxSubArray(b);
         return n<0? 0: n;
    }
};

当然,和我们之前讲过的求最大子段和一样,也可以进行优化。我们注意到在计算最大字段和的函数中只用到了当前的dp[i-1],所以还可以进行优化,边计算差分遍计算最大字段和

int maxProfit(vector<int>& prices) {
         int dp,predp=nums[0];
        int Maxprice=nums[0];
        for(int i=1;i<nums.size();i++)
        {   
            int b=prices[i]-prices[i-1];
            dp=max(b,predp+b);
              Maxprice=max(Maxprice,dp);
              predp=dp;
        }
        return Maxprice;
    }

2、122. 买卖股票的最佳时机

 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票。
 思路:股票问题2与股票问题1的主要区别在于用户可以多次买卖,这里我们还是借助差分数组来做,计算完差分数组,将差分数组中为正数的元素加起来,就是答案。
在这里插入图片描述
  直观的,我们知道,当
第2天买(价格为1),第4天卖(价格为8) 8-1=7
第5天买(价格为3),第6天卖(价格为6) 6-3=3
最大利润为7+3=10
其实就是我们的差分数组为正数的元素的和 4+3+3=10
  股票买卖策略:
1、单独交易日: 设今天价格 p 1 p_1 p1,明天价格 p 2 p_2 p2,则今天买入、明天卖出可赚取金额 p 2 − p 1 p_2 - p_1 p2p1
2、 连续上涨交易日: 设此上涨交易日股票价格分别为 p 1 , p 2 , . . . , p n p_1,p_2,...,p_n p1,p2,...,pn,则最大价值为 p n − p 1 p_n-p_1 pnp1
p n − p 1 = p n − p n − 1 + p n − 1 − p n − 2 + . . . + p 2 − p 1 = d [ n − 1 ] + . . . d [ n ] p_n-p_1=p_n-p_{n-1}+p_{n-1}-p_{n-2}+...+p_2-p_1\\ =d[n-1]+...d[n] pnp1=pnpn1+pn1pn2+...+p2p1=d[n1]+...d[n].
3、 连续下降交易日: 则不买卖收益最大,即不会亏钱。

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        vector<int> d(prices.size()-1,0);
        int ans=0;
        for(int i=0;i<prices.size()-1;i++)
        {
            d[i]=prices[i+1]-prices[i];
        }
        for(auto e:d)
        {
            if(e>0)
            {
                ans+=e;
            }
        }
        return ans;
    }
};

常数优化,边计算差分数组边判断

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int ans=0;
        for(int i=0;i<prices.size()-1;i++)
        {
            if((prices[i+1]-prices[i])>0)
            ans+=(prices[i+1]-prices[i]);
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值