[菜鸟训练]剑指 Offer 63. 股票的最大利润

题目描述:

假设把某股票的价格按照时间先后顺序存储在数组中,请问买卖该股票一次可能获得的最大利润是多少?

示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。

示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

限制:
0 <= 数组长度 <= 10^5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/gu-piao-de-zui-da-li-run-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

采取了三种作法:
第一种,直接暴力,设置一个变量来记录最大值,初始化为0。比如第i天,若该天后的某一天比第i天的价格大,就卖出,然后和最大值进行比较更新。该方法时间复杂度和空间复杂度都比较大,时间复杂度为O(n²)

第二种,利用技巧,我们为了获取最大利益,一定会在当前天的价格最小的时候买入,然后在比此价格高的时候进行卖出。考虑的该点,问题就来了,我们怎样可以确保最后得到的一定是最大利益呢?我们可以造两个变量,一个用来记录当前天及之前的最低价格,一个用来记录当前天的最大利益。某一天存在两种情况:
(1)若今天的价格比最低价格小,说明今天转不了,但是以后有可能回赚的更多,所以就将最低价格进行更新。
(2)若今天的价格比最低价格大,说明今天有利可图,我们就将其卖出来看看自己获取的利益是否大于目前的最大利益,若大于则将最大利益进行更新,不大于不进行任何操作。
这样,执行一遍循环后,所得大的最大利益就是答案。
时间复杂度为O(n)

第三种,使用dp的思想,dp[i]用来存储第i天所能获得的最大利益。当第j天时,
(1)若第j天的价格比最低价格小,则更新最低价格。最大利益和第j-1天的相同
(2)若第j天的价格比最低价格大,则有利可图,卖出后得到的利益与昨天的最大利益也就是dp[j-1]相比较。
时间复杂度比第二种方法略高,整体思想和第二种相同,仅仅是在方法二的基础上加了一个dp的思想,若问题为得到每日的最大利益,该方法则可解决此问题。

代码:

public class jianzhi_Offer_63 {
    
    
    //方法一:暴力,直接把所有情况算出进行比较,取最大。时间空间使用严重 时间复杂度O(n²)
    public int maxProfit(int[] prices) {
    
    
        int maxprice = 0;
        for (int i = 0; i < prices.length; i++){
    
    
            for (int j = i; j < prices.length; j++){
    
    
                int tmp = prices[j] - prices[i];
                maxprice = maxprice < tmp ? tmp:maxprice;
            }
        }
        return maxprice;
    }
    //方法2:我们只需要在当前最低价买入,然后想怎样让股票利益最大化,那不妨每天都卖一次去和当前最大利益比较。
    //如果今天的价格是历史最低,说明转不了,后面有可能赚的比现在多。那我们只需要将记录最低价的变量重新赋值,表示从当前最低价买入
    //如果今天价格比最低价高,说明今天能赚钱,那我们就卖出来看看是否比当前最大利益大。
    //时间复杂度O(n)
    public int maxProfit1(int[] prices) {
    
    
        if(prices.length == 0 ||prices.length == 1){
    
    
            return 0;
        }
        if(prices.length == 2){
    
    
            return prices[0] > prices[1] ? 0 : (prices[1] - prices[0]);
        }
        int maxprice = 0;
        int min = prices[0];
        for (int i = 1; i < prices.length; i++){
    
    
            if(prices[i] < min){
    
    
                min = prices[i];
            }else {
    
    
                maxprice = maxprice < (prices[i] - min) ? (prices[i] - min) : maxprice;
            }
        }
        return maxprice;
    }

    //方法三:使用dp数组,dp[i]存取,到目前第i天的最大利益。
    public int maxProfit2(int[] prices) {
    
    
        if(prices.length == 0 ||prices.length == 1){
    
    
            return 0;
        }
        if(prices.length == 2){
    
    
            return prices[0] > prices[1] ? 0 : (prices[1] - prices[0]);
        }

        int[] dp = new int[prices.length];
        //只有一个数的时候,无利可图
        dp[0] = 0;
        int min = prices[0];
        for (int i = 1; i < prices.length; i++){
    
    
            if(prices[i] < min){
    
    
                min = prices[i];
                dp[i] = dp[i - 1];
            }else {
    
    
                //比较前一天的最大利益和今天卖出的利益哪一个大,从而得到当前最大利益
                dp[i] = Math.max(prices[i] - min, dp[i-1]);
            }
        }
        //最后一天一定是最大利益
        return dp[dp.length - 1];
    }

    public static void main(String[] args) {
    
    
        jianzhi_Offer_63 obj = new jianzhi_Offer_63();

        int[] prices = new int[]{
    
    7,1,5,3,6,4};
        System.out.println(obj.maxProfit2(prices));
    }
}

猜你喜欢

转载自blog.csdn.net/Puppet__/article/details/115052967
今日推荐