I题

Say you have an array for which the ith element is the price of a given stock on day i.

If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm to find the maximum profit.

Subscribe to see which companies asked this question

解答:

采用动态规划解法,遍历数组更新当前最小值,并用当前值减去最小值与当前最大利润进行比较,更新最大利润。

public class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) {
return 0;
}
int min = Integer.MAX_VALUE;
int profit = 0;
for (int i : prices) {
min = Math.min(min, i);
profit = Math.max(i - min, profit);
}
return profit;
}
}

II

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times). However, you may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

Subscribe to see which companies asked this question

解答:

采用贪心算法,记录相邻两天的差值,大于零则加到利润总量中。(本题满足贪心算法可以得到最优解的特性是重点)

public class Solution {
public int maxProfit(int[] prices) {
int profit = 0;
for (int i = 0; i < prices.length - 1; i++) {
int pro = prices[i + 1] - prices[i];
if (pro > 0) {
profit += pro;
}
}
return profit;
}
}

Best Time to Buy and Sell Stock with Cooldown

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

  • You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
  • After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)

Example:

prices = [1, 2, 3, 0, 2]
maxProfit = 3
transactions = [buy, sell, cooldown, buy, sell]

解答:

设置三个数组,buy sell和rest。

buy[i]表示第i天以buy状态结束时至今可以获得的最大profit;

sell[i]表示第i天以sell状态结束至今可以获得的最大profit;

rest[i]表示第i天以rest状态结束至今可以获得的最大profit。

根据定义可得:

buy[i]  = max(rest[i-1]-price, buy[i-1]) //前者表示在前一天rest的情况下今天购入,后者表示在前一天处于buy状态的情况下保持buy状态(即不操作)
sell[i] = max(buy[i-1]+price, sell[i-1]) //前者表示在前一天处于buy状态的情况下今天卖出,后者表示前一天已经处于sell状态的情况下保持sell状态(即不操作)
rest[i] = max(sell[i-1], buy[i-1], rest[i-1]) //rest表示没有任何操作,所以其值应为前一天处于sell,buy和rest状态中的最大值

上述等式考虑了两个规则,即buy必须在rest之后,sell必须在buy之后,由一式和二式可以得到。但还有一个特殊情况[buy,rest,buy]需要考虑,从上述三式不能明显得出这种特殊情况不存在。

由buy[i] <= rest[i],故rest[i] = max(sell[i-1], rest[i-1]),由此式可以得到[buy,rest,buy]不可能发生。

由rest[i] <= sell[i],故rest[i] = sell[i-1]。

于是上述三个等式可以化为两个:

buy[i] = max(sell[i-2]-price, buy[i-1])
sell[i] = max(buy[i-1]+price, sell[i-1])

第i天状态只和第i-1天和i-2天有关,所以空间可以由O(n)缩小为O(1)。

具体代码如下:

public int maxProfit(int[] prices) {
int sell = 0, prev_sell = 0, buy = Integer.MIN_VALUE, prev_buy;
for (int price : prices) {
prev_buy = buy;
buy = Math.max(prev_sell - price, prev_buy);
prev_sell = sell;
sell = Math.max(prev_buy + price, prev_sell);
}
return sell;
}

III

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most two transactions.

Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).

问题分析:

最初的想法是在prices数组中寻找一个分割点,把数组分割为两部分。然后利用第一个问题的方法去分别寻找两部分的结果,将结果相加,得出的最大结果即为最终的最大利润。代码如下:

public class Solution {
public int maxProfit(int[] prices) {
int n = prices.length;
int rst = 0;
for (int i = 0; i < n; i++) {
int temp = helper(prices, 0, i) + helper(prices, i + 1, n - 1);
if (rst < temp) {
rst = temp;
}
}
return rst;
}
public int helper(int[] prices, int i, int j) {
if (i > j) return 0;
int min = Integer.MAX_VALUE;
int rst = 0;
for (int k = i; k <= j; k++) {
min = Math.min(prices[k], min);
rst = Math.max(prices[k] - min, rst);
}
return rst;
}
}

这段代码在lintcode上通过了所有test case,但是在leetcode上超时了。时间复杂度为O(n^2).

利用数组dp[k][i]来表示以在prices下标i之前(包含i)进行k次交易得到的最大利润。则可以得到递推公式为

dp[k][i] = max(dp[k][i - 1], max(dp[k - 1][j] + prices[i] - prices[j])), 其中j的取值范围为[0, i - 1].

= max(dp[k][i - 1], prices[i] + max(dp[k -1][j] - prices[j]))

= max(dp[k][i - 1], prices[i] + max(prev[k - 1])), 在内层循环中只需要每次更新这个值即可。

根据实际意义,dp[0][i]和dp[i][0]均为0. 

具体代码如下:

public class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length <= 1) return 0;
int k = 2;
int[][] dp = new int[k + 1][prices.length];
for (int t = 1; t <= k; t++) {
int tmp = Integer.MIN_VALUE;
for (int i = 1; i < prices.length; i++) {
tmp = Math.max(tmp, dp[t - 1][i - 1] - prices[i - 1]);
dp[t][i] = Math.max(dp[t][i - 1], prices[i] + tmp);
}
}
return dp[k][prices.length - 1];
}
}

问题优化:

考虑此时能否把二维数组简化为一维数组,发现tmp既与i的上一个状态有关,还与t的上一个状态有关。此时不方便简化。

仔细分析发现在递推公式dp[k][i] = max(dp[k][i - 1], max(dp[k - 1][j] + prices[i] - prices[j]))中j取i时也可行。也就意味着在内部循环式变为

1)tmp = Math.max(tmp, dp[t - 1][i] - prices[i])

2)dp[t][i] = Math.max(dp[t][i - 1], prices[i] + tmp)

此时将数组简化为一维数组dp[i]每次用i - 1的状态更新i的状态即可,具体代码如下:

public class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length <= 1) return 0;
int k = 2;
int[] dp = new int[prices.length];
for (int t = 1; t <= k; t++) {
int tmp = dp[0] - prices[0];
for (int i = 1; i < prices.length; i++) {
tmp = Math.max(tmp, dp[i] - prices[i]);
dp[i] = Math.max(dp[i - 1], prices[i] + tmp);
}
}
return dp[prices.length - 1];
}
}

进一步优化:

考虑问题的继续优化,dp[i]只与dp[i - 1]有关,并且k = 2时外层循环只有两次,所以只需要四个变量来记录变化即可。

此时只需要对prices进行遍历,更新这四个变量即可。具体意义为:

1)buy1:当前购买了第一支股票的最大获利;

2)sell1:当前售出了第一支股票的最大获利;

3)buy2:当前购买了第二支股票的最大获利;

4)sell2:当前售出了第二支股票的最大获利。

public class Solution {
public int maxProfit(int[] prices) {
if (prices == null || prices.length <= 1) return 0;
int buy1 = Integer.MIN_VALUE;
int buy2 = Integer.MIN_VALUE;
int sell1 = 0;
int sell2 = 0;
for (int i : prices) {
buy1 = Math.max(buy1, - i);
sell1 = Math.max(sell1, i + buy1);
buy2 = Math.max(buy2, sell1 - i);
sell2 = Math.max(sell2, i + buy2);
}
return sell2;
}
}

IV

Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete at most k transactions.

问题解答:

这里用III中的普适方法会有一个test case出现MLE的问题,原因是k值过大。在这里对于k值比二分之一数组长度大时,问题可以简化为问题II。采用quickSolve方法解决此时的问题,代码如下:

public class Solution {
public int maxProfit(int k, int[] prices) {
if (prices == null || prices.length <= 1) return 0;
if (k >= prices.length / 2) return quickSolve(prices);
int[][] dp = new int[k + 1][prices.length];
for (int t = 1; t <= k; t++) {
int tmp = dp[t - 1][0] - prices[0];
for (int i = 1; i < prices.length; i++) {
dp[t][i] = Math.max(dp[t][i - 1], prices[i] + tmp);
tmp = Math.max(tmp, dp[t - 1][i] - prices[i]);
}
}
return dp[k][prices.length - 1];
}
public int quickSolve(int[] prices) {
int rst = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
rst += prices[i] - prices[i - 1];
}
}
return rst;
}
}

Best Time to Buy and Sell Stock系列的更多相关文章

  1. LeetCode -- Best Time to Buy and Sell Stock系列

    Question: Best Time to Buy and Sell Stock Say you have an array for which the ith element is the pri ...

  2. Java for LeetCode 188 Best Time to Buy and Sell Stock IV【HARD】

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  3. [LeetCode] Best Time to Buy and Sell Stock III 买股票的最佳时间之三

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  4. 【LeetCode】Best Time to Buy and Sell Stock IV

    Best Time to Buy and Sell Stock IV Say you have an array for which the ith element is the price of a ...

  5. [leetcode]_Best Time to Buy and Sell Stock I && II

    一个系列三道题,我都不会做,google之答案.过了两道,第三道看不懂,放置,稍后继续. 一.Best Time to Buy and Sell Stock I 题目:一个数组表示一支股票的价格变换. ...

  6. Maximum Subarray / Best Time To Buy And Sell Stock 与 prefixNum

    这两个系列的题目其实是同一套题,可以互相转换. 首先我们定义一个数组: prefixSum (前序和数组) Given nums: [1, 2, -2, 3] prefixSum: [0, 1, 3, ...

  7. 【一天一道LeetCode】#122. Best Time to Buy and Sell Stock II

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Say you ...

  8. [LeetCode] Best Time to Buy and Sell Stock with Cooldown 买股票的最佳时间含冷冻期

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

  9. [LeetCode] Best Time to Buy and Sell Stock IV 买卖股票的最佳时间之四

    Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...

随机推荐

  1. ROM与RAM知识

    “ROM”和“RAM”的意思: “ROM”:N年前代表一种只能写入和读取,而不能改写和擦除的设备,可以用光驱CD-ROM来说明这个道理.目前的“ROM”已经不是这个道理了,它的技术已经飞快的发展到现在 ...

  2. 2017年2月16日-----------乱码新手自学.net 之MVC模型

    第二篇博文,最近学习的内容还是回到了正题:ASP.NET MVC5之上.虽然EF学了个一知半解,但是用这点知识,看MVC5的MODEL部分应该还是够了.尽管周末还要恶补一下EF才行. (一)MVC简述 ...

  3. framework各版本新特性(为面试准备)

    菜鸟D估计描述这些新特性的文章都是烂大街的货色,之所以拿出来分(e)享(xin)一下,有两个原因:1.当年面试的时候有人问到,我不知道该怎么回答:2.项目需要发布了,但是考虑到framework的版本 ...

  4. BZOJ 1198: [HNOI2006]军机调度(搜索)

    直接暴搜就行了= = CODE: #include<cstdio> #include<iostream> #include<cstring> #include< ...

  5. 深度了解Android 7.0 ,你准备好了吗?

    作者:Redyan, 腾讯移动客户端开发工程师 商业转载请联系腾讯WeTest获得授权,非商业转载请注明出处. 原文链接:http://wetest.qq.com/lab/view/288.html ...

  6. 归纳篇(一)CSS的position定位和float浮动

    近期会更新一系列博客,对基础知识再度做个巩固和梳理. 一.position定位 (一):position的属性 1.absolute:生成绝对定位的元素,相对于最近一级定位不是static的父元素来进 ...

  7. NoSql研究报告

    NoSql研究报告 1.概述 随着互联网的不断发展,信息系统的数据变得越来越多,关系型数据库逐渐面临着难以克服的障碍,主要体现在: 对数据库的高并发读写需求 对海量数据的高效率存储和访问需求 对数据库 ...

  8. 杭电OJ2005——第几天

    /*第几天?Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submi ...

  9. VUE2.0实现购物车和地址选配功能学习第五节

    第五节 单件商品金额计算和单选全选功能 1.vue精髓在于操作data模型来改变dom,渲染页面,而不是直接去改变dom 2.加减改变总金额功能: html:<div class="c ...

  10. 转 jquery怎么在header中设置请求信息

    jquery是js的类库,js本身不能操作header,因为js是在浏览器加载页面过程中才开始执行的 header需要服务器端执行操作 如果是ajax,是可以设置header $.ajax({ url ...