• LeetCode> 121. 买卖股票的最佳时机(三种解法)


    题目

    对于非负整数 X 而言,X 的数组形式是每位数字按从左到右的顺序形成的数组。例如,如果 X = 1231,那么其数组形式为 [1,2,3,1]。

    给定非负整数 X 的数组形式 A,返回整数 X+K 的数组形式。

    示例 1:

    输入:A = [1,2,0,0], K = 34
    输出:[1,2,3,4]
    解释:1200 + 34 = 1234
    

    示例 2:

    输入:A = [2,7,4], K = 181
    输出:[4,5,5]
    解释:274 + 181 = 455
    

    示例 3:

    输入:A = [2,1,5], K = 806
    输出:[1,0,2,1]
    解释:215 + 806 = 1021
    

    示例 4:

    输入:A = [9,9,9,9,9,9,9,9,9,9], K = 1
    输出:[1,0,0,0,0,0,0,0,0,0,0]
    解释:9999999999 + 1 = 10000000000
    

    提示:

    1 <= A.length <= 10000
    0 <= A[i] <= 9
    0 <= K <= 10000
    如果 A.length > 1,那么 A[0] != 0
    

    解题思路

    方法一:暴力搜索
    T(n)=O(n^2)
    遍历价格数组, 求解以当天为卖出日期的最大值. 得到一个针对每天卖出股票的利润最大值数组, 数组的最大值, 即为利润最大值

        /**
         * 方法一: 暴力搜索, T(n)=O(n^2)
         * 遍历价格数组, 求解以当天为卖出日期的最大值. 得到一个针对每天卖出股票的利润最大值数组, 数组的最大值, 即为利润最大值
         */
        public int maxProfit(int[] prices) {
            if (prices == null || prices.length < 1) return 0;
            int max = 0;
    
            for (int i = 1; i < prices.length; i++) {
                for (int j = 0; j < i && j < prices.length; j++) {
                    int profit = prices[i] - prices[j];
                    if (profit > max) max = profit;
                }
            }
    
            return max;
        }
    

    方法二:动态规划
    T(n) = O(n)
    先求出到第i天时利润最大值dp[i], 到最后一天时, 利润最大值就是dp[i]。
    dp[i]的求法, 分为两种可能情况:
    1.第i天有卖出, 也就是0..i-1天中股价最小时买入, 第i天卖出;
    2.第i天没有卖出, 利润最大值同第i-1天。

    /**
     * 方法二: 动态规划, T(n) = O(n)
     * 先求出到第i天时利润最大值dp[i], 到最后一天时, 利润最大值就是dp[i]
     * dp[i]的求法, 分为两种可能情况: 
     * 1.第i天有卖出, 也就是0..i-1天中股价最小时买入, 第i天卖出;
     * 2.第i天没有卖出, 利润最大值同第i-1天.
      */
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length < 1) return 0;
    
        int min = prices[0];
        int[] dp = new int[prices.length];
        dp[0] = 0;
        for (int i = 1; i < dp.length; i++) {
            if (prices[i-1] < min) min = prices[i-1];
            dp[i] = Math.max(dp[i-1], prices[i] - min);
        }
    
        return dp[dp.length-1];
    }
    

    方法三:分治法
    T(n) = O(nlgn)
    先求出每天股票变化值(prices[i]-prices[i-1]), 问题转化为求解(和)最大连续子数组
    数组A[low..high]中的最大连续子数组A[left..right]分为三种情况:

    1. 子数组全部落到左半部, 即low <= left < right <= mid;
    2. 子数组全部落到右半部, 即mid < left < right <= high;
    3. 子数组跨越中点, 即low <= left <= mid < right <= high;
      情形1和2, 是求解最大连续子数组的子问题, 可以递归求解. 情形3有特殊限制, 需要专门讨论如何处理
    /**
     * 方法三: 分治法, T(n) = O(nlgn)
     * 先求出每天股票变化值(prices[i]-prices[i-1]), 问题转化为求解(和)最大连续子数组
     * 数组A[low..high]中的最大连续子数组A[left..right]分为三种情况:
     * 1. 子数组全部落到左半部, 即low <= left < right <= mid;
     * 2. 子数组全部落到右半部, 即mid < left < right <= high;
     * 3. 子数组跨越中点, 即low <= left <= mid < right <= high;
     * 情形1和2, 是求解最大连续子数组的子问题, 可以递归求解. 情形3有特殊限制, 需要专门讨论如何处理
     */
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length < 1) return 0;
    
        for (int i = prices.length-1; i > 0; i--) {
            prices[i] = prices[i] - prices[i-1];
        }
        prices[0] = 0;
    
        int[] res = findMaximumSubArray(prices, 0, prices.length-1);
    
        return res[2];
    }
    
    public int[] findMaxCrossingSubArray(int[] A, int low, int mid, int high) {
    
        int leftSum = Integer.MIN_VALUE;
        int maxLeft = mid;
        int sum = 0;
        for (int i = mid; i >= low ; i--) {
            sum += A[i];
            if (sum > leftSum) {
                leftSum = sum;
                maxLeft = i;
            }
        }
    
        int rightSum = Integer.MIN_VALUE;
        int maxRight = mid;
        sum = 0;
        for (int j = mid+1; j <= high; j++) {
            sum += A[j];
            if (sum > rightSum) {
                rightSum = sum;
                maxRight = j;
            }
        }
    
        return new int[]{maxLeft, maxRight, (leftSum + rightSum)};
    }
    
    public int[] findMaximumSubArray(int[] A, int low, int high) {
        if (low == high) {
            return new int[]{low, high, A[low]};
        }
        else {
            int mid = (low + high) / 2;
            int[] leftRes = findMaximumSubArray(A, low, mid);
            int[] rightRes = findMaximumSubArray(A, mid+1, high);
            int[] crossRes = findMaxCrossingSubArray(A, low, mid, high);
    
            if (leftRes[2] >= rightRes[2] && leftRes[2] >= crossRes[2])
                return leftRes;
            else if(rightRes[2] >= leftRes[2] && rightRes[2] >= crossRes[2])
                return rightRes;
            else return crossRes;
        }
    }
    

    Ref
    LeetCode 121. 买卖股票的最佳时机

  • 相关阅读:
    innodb临键锁锁定范围
    详解 MySql InnoDB 中的三种行锁(记录锁、间隙锁与临键锁)
    解决Jenkins邮件配置问题
    解决import模块后提示无此模块的问题
    【转】Linux下cp: omitting directory `XXX'问题解决
    Python之异常处理(执行python文件时传入参数)
    Python之发邮件
    Python之递归
    Python之参数类型、变量
    linux sed命令详解
  • 原文地址:https://www.cnblogs.com/fortunely/p/14117278.html
Copyright © 2020-2023  润新知