[LeetCode] 122. Best Time to Buy and Sell Stock II

You are given an integer array prices where prices[i] is the price of a given stock on the ith day.

On each day, you may decide to buy and/or sell the stock. You can only hold at most one share of the stock at any time. However, you can buy it then immediately sell it on the same day.

Find and return the maximum profit you can achieve.

Example 1:

Input: prices = [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.
Total profit is 4 + 3 = 7.

Example 2:

Input: prices = [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
Total profit is 4.

Example 3:

Input: prices = [7,6,4,3,1]
Output: 0
Explanation: There is no way to make a positive profit, so we never buy the stock to achieve the maximum profit of 0.

Constraints:

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices[i] <= 104

买卖股票II。

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

这个题跟版本一的要求几乎一致,只是版本一要求只能买卖一次;版本二是可以买卖任意次数,也是求最大利润。这题也是有两种做法,一是贪心,一是动态规划。

首先是贪心。贪心的来源,是因为不限买卖次数,所以只要下一个点的股价比上一个点高,就做交易。

时间O(n)

空间O(1)

JavaScript实现

 1 /**
 2  * @param {number[]} prices
 3  * @return {number}
 4  */
 5 var maxProfit = function (prices) {
 6     // corner case
 7     if (prices === null || prices.length < 2) return 0;
 8 
 9     // normal case
10     let profit = 0;
11     for (let i = 1; i < prices.length; i++) {
12         if (prices[i] > prices[i - 1]) {
13             profit += prices[i] - prices[i - 1];
14         }
15     }
16     return profit;
17 };

 

Java实现

 1 class Solution {
 2     public int maxProfit(int[] prices) {
 3         // corner case
 4         if (prices == null || prices.length == 0) {
 5             return 0;
 6         }
 7         
 8         // normal case
 9         int profit = 0;
10         for (int i = 1; i < prices.length; i++) {
11             if (prices[i] > prices[i - 1]) {
12                 profit += prices[i] - prices[i - 1];
13             }
14         }
15         return profit;
16     }
17 }

 

动态规划的思路跟版本一很接近。设一个二维数组 dp[][] 其中第一维的长度是数组的长度 len,第二维的长度是 2,只有可能是 0 或 1,表示不持股和持股。这里第一维代表的就是遍历到某个位置的 DP 值,第二维表示的是在当前位置是否持有股票。持有记为 1,不持有记为 0。每个位置 dp[i][j] 的定义是第 i 天的时候我们持股与否的最大收益。注意这里的不持有不是一直不买,而是卖出之后的不持有。版本二的一个引用

这里DP值的更新细节如下

dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);

这一行的意思是在某一个位置如果不持有股票,那么他的DP值有可能是因为前一天也不持股,或者是今天卖了股票而得到的

dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);

这一行的意思是在某一个位置如果持有股票,那么他的DP值有可能是因为上一个位置也持有股票,或者是今天买了股票导致的。这个地方的定义跟版本一很接近,区别在于版本一只能买卖一次,所以买的那一次是不依赖 dp[i - 1][0] 的值的,因为不持有股票的时候收益就是 0。但是这道题因为允许多次交易所以 dp[i - 1][0] 有可能携带了前面几次交易的收益,这个信息不能丢失。

时间O(n)

空间O(n)

Java实现

 1 class Solution {
 2     public int maxProfit(int[] prices) {
 3         int len = prices.length;
 4         // corner case
 5         if (len < 2) {
 6             return 0;
 7         }
 8         // 0:持有现金
 9         // 1:持有股票
10         // 状态转移:0 → 1 → 0 → 1 → 0 → 1 → 0
11         int[][] dp = new int[len][2];
12         // 第一天不持有股票,收益就是0;买了股票,收益就是-prices[0],可理解为成本
13         dp[0][0] = 0;
14         dp[0][1] = -prices[0];
15         for (int i = 1; i < len; i++) {
16             // 今天不持有股票的收益来自于昨天不持有股票或今天卖了股票之后的较大值
17             dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
18             // 今天持有股票的收益来自于昨天持有股票或今天买了股票之后的较大值
19             dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
20         }
21         return dp[len - 1][0];
22     }
23 }

 

由于每天持有股票和不持有股票的最大收益只取决于前一天的情况,这里我们可以节省空间。

时间O(n)

空间O(1)

Java实现

 1 class Solution {
 2     public int maxProfit(int[] prices) {
 3         // corner case
 4         int len = prices.length;
 5         if (len < 2) {
 6             return 0;
 7         }
 8         
 9         // normal case
10         int cash = 0;
11         int hold = -prices[0];
12         int preCash = cash;
13         int preHold = hold;
14         for (int i = 1; i < len; i++) {
15             cash = Math.max(preCash, preHold + prices[i]);
16             hold = Math.max(preHold, preCash - prices[i]);
17             preCash = cash;
18             preHold = hold;
19         }
20         return cash;
21     }
22 }

 

LeetCode 题目总结

posted @ 2020-02-17 13:17  CNoodle  阅读(419)  评论(0编辑  收藏  举报