zoukankan      html  css  js  c++  java
  • 【LeetCode】714、买卖股票的最佳时机含手续费

    Best Time to Buy and Sell Stock with Transaction Fee

    题目等级:Medium

    题目描述:

    Your are given an array of integers prices, for which the i-th element is the price of a given stock on day i; and a non-negative integer fee representing a transaction fee.

    You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction. You may not buy more than 1 share of a stock at a time (ie. you must sell the stock share before you buy again.)

    Return the maximum profit you can make.

    Example 1:

    Input: prices = [1, 3, 2, 8, 4, 9], fee = 2
    Output: 8
    Explanation: The maximum profit can be achieved by:
    Buying at prices[0] = 1
    Selling at prices[3] = 8
    Buying at prices[4] = 4
    Selling at prices[5] = 9
    The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
    

      题意:给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。可以无限次地完成交易,但是每次交易都需要付手续费。返回获得利润的最大值。


    解题思路(动态规划):

      终于到了买卖股票的最后一道题。。。

      有了上一题(冷冻期)的经验,这道题实际不难了,同样是无数次情况的一个变形,只不过每次需要交一定的费用。实际很类似,有了上一题状态的定义,稍加修改就是这个题了。

      同样的,每一天是一个阶段,每一阶段的决策就是:每天决定买还是卖,而每一天有两个状态:手里持有股票、手里没有股票

      和上题一样,仍然定义两个状态变量:

      sell[i]:表示在第i天结束后手里没有股票的情况下,获得的最大收益。

      hold[i]:表示在第i天结束后手里仍然持有股票的情况下获得的最大收益。

      其状态转移也不难分析:

      如果当天结束时仍然持有股票,那么有两种可能:(1)今天刚买的,那么说明前一天结束的时候手里没有股票了,即hold[i]=sell[i-1]-prices[i]. (2)以前就买了,今天啥也没干,也没买也没卖,换句话说就是前一天结束的时候手里已经有了,即:hold[i]=hold[i-1]

      如果当天结束的时候手里没有股票,那么说明也有两种可能:(1)今天刚卖了, 也就是说前一天结束的时候手里还是持有股票的,而今天卖的时候还有交纳费用,所以:sell[i]=hold[i-1]+prices[i]-fee.(2)以前就卖了,今天啥也没干,那说明前一天结束的时候手里已经没有股票了,所以:sell[i]=sell[i-1].

      综合起来,就可以得到状态转移方程:

    	hold[i]=max(sell[i-1]-prices[i],hold[i-1])
    	sell[i]=max(hold[i-1]+prices[i]-fee,sell[i-1])
    

      初始条件还是一样的,第一天的时候不可能卖出,一定会买入,这实际上还是贪心思想的一种体现,第一天可以买一定是会买的,在处理不限次数的交易时,已经证明了这种贪心思想的正确性,所以sell[0]=0,而hold[0]=-prices[0].

      最后,根据以上分析给出以下代码:

        public int maxProfit(int[] prices, int fee) {
            if(prices==null || prices.length==0)
                return 0;
            int len=prices.length;
            int[] sell=new int[len];
            int[] hold=new int[len];
            sell[0]=0;
            hold[0]=-prices[0];
            for(int i=1;i<len;i++){
                sell[i]=Math.max(sell[i-1],hold[i-1]+prices[i]-fee);
                hold[i]=Math.max(sell[i-1]-prices[i],hold[i-1]);
            }
            return sell[len-1];
        }
    }
    

      时间复杂度:O(n),空间复杂度:O(2n)

    总结

      本题是买卖股票6道题的最后一题了,做一个简单的总结,这一系列题目是动态规划和贪心思想的运用。我们可以看到:实际上在冷冻期和需要费用的这两道题目中定义的两个状态sell和hold是可以解决所有的不限制交易次数的题目的,包括我们的无数次交易也可以通过这两个状态来写出转移方程,因为不管条件如何变,只要没有限制交易次数,每天的状态都还是这两个。而限制了交易次数的,状态就会复杂一些,就需要一个二维状态,这也就是在允许交易K次的题目中我们给出的方法。

      因此,到此为止,不管股票买卖这道题再给出什么条件,我们都可以做了,因为限制次数的和不限制次数的两种情况下的状态我们都清楚了,只需要根据不同的条件写出转移方程就可以了。

      一次交易:【LeetCode】121、买卖股票的最佳时机

      两次交易:【LeetCode】123、买卖股票的最佳时机 III

      K次交易:【LeetCode】188、买卖股票的最佳时机 IV

      无数次交易:【LeetCode】122、买卖股票的最佳时机 II

      无数次交易含冷冻期:【LeetCode】309、最佳买卖股票时机含冷冻期

      无数次交易含交易费用:【LeetCode】714、买卖股票的最佳时机含手续费

  • 相关阅读:
    linux 程序安装目录/opt目录和/usr/local目录的区别
    Linux文件目录结构详解
    Jenkins卸载方法(Windows/Linux/MacOS)
    Jmeter案例demo
    idea打包java可执行jar包
    查看端口状态
    轻松掌握mongodb
    sphinx和coreseek
    redis
    redis默认端口6379以其名命名,是我孤陋寡闻了,是名性感美女(梅尔兹)
  • 原文地址:https://www.cnblogs.com/gzshan/p/11123013.html
Copyright © 2011-2022 走看看