LeetCode 股票系列(三)

简介: LeetCode 股票系列(三)

今天我们来继续聊聊 Leetcode 的华尔街之狼(The Wolf of Wall Street)系列,也称股票系列, 在 Leetcode 上有 6 题之多。

今天讲解的是第三题,与前两题相比升级了一点难度,我们一起来看下。


3. Best Time to Buy and Sell Stock with Transaction Fee && Best Time to Buy and Sell Stock II

题意:

同样还是给你一组数组代表每一天的股价,这次我们可以进行多次买卖,但是每一次买卖你需要多付一个fee。例如,prices = [1,3,2,8,4,9], fee = 2

我们可以在第1天买第4天卖和第5天买第6天卖,总收益是(8-1-2) + (9-4-2) = 8,这是我们能得到的最大收益。

这里我们两题一起讲,因为他们是一样的,Best Time to Buy and Sell Stock II 其实就是fee=0 的情况,如果我们能做出Best Time to Buy and Sell Stock with Transaction Fee,Best Time to Buy and Sell Stock II 就迎刃而解了。

问题分析 :

与之前的问题一样,我们可以试着枚举买或者卖。

但是因为这次不只是只有一次操作这么简单,如果我们在 j 天进行购买和 i 天进行卖 (j<i), prices[0 : j-1] 可能还存在着其它的交易。

我们试着像第一题的方法1一样先从暴力入手,去试着枚举 (买,卖) pair。

如果我们在i天进行卖和j天进行买,他的单次交易 (singleTransaction) 能得到的利益是 prices[i]-prices[j]-fee

但我们别忘了,我们prices[0 : j-1] 还可以进行其它的交易。

所以我们可以用一个 dp 去记录,dp[i] 表示 prices[0:i] 能得到的最大收益。

所以如果我们在 i天卖和在j 天买,那么我们能得到的最大收益就是 prices[i]-prices[j]-fee+dp[j-1]

现在我们剩下的问题就是如何去计算dp[i],如果我们在i 天进行卖,j 进行买,那么如果我们枚举所有 j 的 可能性的话,dp[i]=max(prices[i] - prices[j]-fee + dp[j-1])

但是我们别忘了一件事,我们在i 这天也可以不进行任何的操作,所以还要跟 dp[i-1] 进行比较。

综上,dp[i]=max(dp[i-1], max(prices[i] - prices[j]-fee + dp[j-1]))

方法1:暴力解

public int maxProfit(int[] prices, int fee) {
   int n = prices.length;
   int dp[] = new int[n];//dp[i]表示 [0:i]的最大收益
   for (int i = 1; i < n; i++) {//枚举i,i是卖的天数
     dp[i] = dp[i - 1];
     for (int j = i - 1; j >= 0; j--) {//j 是买的天数,j<i
       int singleTransaction = Math.max(0, prices[i] - prices[j] - fee);
       //注意outbound
       if (j - 1 >= 0) {
         dp[i] = Math.max(dp[i], singleTransaction + dp[j - 1]);
       } else {
         dp[i] = Math.max(dp[i], singleTransaction);
       }
     }
   }
   return dp[n - 1];
 }

代码总结:

  • 暴力的dp,我们还会通过仔细观察 dp 的关系转移去进行深一步的优化

空间复杂度和时间复杂度:

  • 时间复杂度:O(N^2)
  • 空间复杂度:O(N)

方法2:优化DP

我们可以从 dp 的关系转移中进行优化:

方法1我们可以看出 dp[i]=max(dp[i-1], max(prices[i] - prices[j]-fee + dp[j-1])),从这转移式中我们可以发现 i 是一个不变量,而 j 是变量。

首先,我们设dp[i]=dp[i-1]

我们再仔细的观察一下这个式子 prices[i] - prices[j]-fee + dp[j-1],当我们枚举 i 的时候,我们会发现prices[i] - fee 是个常数!

我们如果把式子重新整理一下,那它就是 (prices[i] - fee) - (prices[j] - dp[j-1])

我们要是想整个式子的值越大,变量部分prices[j] - dp[j-1] 就得越小。

如果我们在 i 进行dp[i] = (prices[i] - fee) - min(prices[j] - dp[j-1]),我们可以用一个min 去记录 prices[j] - dp[j-1],一边遍历一边update。

没错,跟第一题的操作是完全一样的。

public int maxProfit(int[] A, int fee) {
  int n = A.length;
  int dp[] = new int[n];
  int min = A[0];
  for (int i = 1; i < A.length; i++) {
    int cur = A[i] - fee;
    dp[i] = dp[i - 1];
    dp[i] = Math.max(dp[i], cur - min);
    min = Math.min(min, A[i] - dp[i - 1]); 
  }
  return dp[n - 1];
}

代码总结:

  • DP 其实就是一种关系(式子)的转化,当我们求出他的基本关系的时候,我们可以看看能不能通过它的关系进行优化

空间复杂度和时间复杂度:

  • 时间复杂度:O(N)
  • 空间复杂度:O(N)


目录
相关文章
|
2月前
|
算法
《LeetCode》—— 买卖股票的最佳时机
《LeetCode》—— 买卖股票的最佳时机
|
2月前
|
算法 索引
leetcode代码记录(买卖股票的最佳时机
leetcode代码记录(买卖股票的最佳时机
25 1
|
1月前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
|
26天前
|
算法
leetcode题解:121.买卖股票的最佳时机
leetcode题解:121.买卖股票的最佳时机
16 0
|
1月前
|
存储 算法 数据可视化
LeetCode 力扣题目:买卖股票的最佳时机 IV
LeetCode 力扣题目:买卖股票的最佳时机 IV
|
1月前
|
存储 算法 数据可视化
LeetCode 力扣题目:买卖股票的最佳时机 III
LeetCode 力扣题目:买卖股票的最佳时机 III
|
1月前
|
存储 算法 数据可视化
买卖股票的最佳时机 II(LeetCode 122)
买卖股票的最佳时机 II(LeetCode 122)
|
1月前
|
存储 算法 数据可视化
LeetCode 题目 121:买卖股票的最佳时机
LeetCode 题目 121:买卖股票的最佳时机
|
2月前
|
算法
leetcode代码记录(买卖股票的最佳时机 III
leetcode代码记录(买卖股票的最佳时机 III
24 5
|
2月前
|
算法
leetcode代码记录(买卖股票的最佳时机 IV
leetcode代码记录(买卖股票的最佳时机 IV
27 2