赞
踩
准备总结一下做过的几道买卖股票的题目,还有几道还没来得及做,先把做过的做一个总结,以便日后忘了,留作复习使用。
题目难度又简到难。(一些题目直接参考的是官方题解)。有很多地方理解不到位或者是表述不清,但是还是先做个笔记,方便理解吧。
最大收益就是需要在较低的价格买入,较高的价格卖出。遍历数组,找到当前天数i之前的股票价格的最小值min,如果存在,则当前日期的收益为prices[i] - min;如果找不到,说明当前日期的股票价格是目前遍历过的数组元素中最低的,将min的值设置为当前日期的股票价格。
细节处理,在第一天时,只能买入股票或者是不做任何操作,而不能卖出股票,设置min初始值为Integer.MAX_VALUE,与prices[0]比较,初始值被修改为prices[0]。
class Solution {
public int maxProfit(int[] prices) {
int res = 0;
if(prices.length<2){
return res;
}
int min = Integer.MAX_VALUE;
for(int i=0;i<prices.length;i++){
if(min>prices[i]){
min = prices[i];
}else{
res = Math.max(res,prices[i] - min);
}
}
return res;
}
}
与题目一相比,不同点在于股票交易的次数不受限制了,目的仍是追求最大利益。题目核心是贪心算法。
为了追求利益的最大化,我们在价格低点买入股票,在上涨的最高点卖出股票。假设我们在第i天买入,第i+1、i+2、……、i+j天都在上涨,我们在这几天都保持持有,不做卖出操作,遍历到第i+j+1天时,价格较第i+j天相比下降,则在第i+j天卖出,在第i+j+1天买入(如果第i+j+2天的价格较第i+j+1天就像下降,则选择在第i+j+2天买入)。
这样的过程实质相当于在价格数组找到多个连续递增的子序列。
min记录的是买入时的价格,max记录的是卖出时的价格。
class Solution {
public int maxProfit(int[] prices) {
int profit = 0, max = prices[0], min = prices[0];
if(prices.length<2)
return profit;
for(int i=1;i<prices.length;i++){
if(prices[i]>prices[i-1])
{
max = prices[i];
if(i==prices.length-1)
{
profit = profit +max - min;
}
}
else
{
profit = profit +max - min;
max = prices[i];
min = prices[i];
}
}
return profit;
}
}
可以对上述代码作出简化:
class Solution {
public int maxProfit(int[] prices) {
int res = 0;
if(prices.length<2){
return res;
}
for(int i=1;i<prices.length;i++){
res+=Math.max(0,prices[i] - prices[i-1]);
}
return res;
}
}
这道题相当于在题目二的基础上增加了手续费这一限制因素。
买卖股票这种题目其实可以记录两种状态,因为每天可以采取的措施就是买入和卖出两种,我们在这两种操作中选择利益最大的那个即可,其次理清题目的逻辑即可。
记录两种状态,第一种是买入buy(如果当前天数i的前一天不持有股票,则在第i天买入,需要用前一天的累计收益sell[i-1]减去成本prices[i];如前一天持有股票,则继续持有即可),记录的是当前日期第i天买入后的收益;第二种状态是卖出sell(如果当前日期第i天 的前一天手上不持有股票,则无法卖出,持有收益与前一天相同;如果前一天持有股票,则计算卖出的收益buy[i-1]+prices[i],同时减去手续费),记录的当前日期第i天卖出后的累计收益。
用计算式表达上述情况如下:
buy[i] = Math.max(buy[i-1],sell[i-1] - prices[i])
sell[i] = Math.max(buy[i-1]+prices[i]-fee,sell[i-1])
考虑边界问题,开始第一天,无法卖出,故将卖出的收益设置为sell[0] = 0,代表卖出收益为0,符合逻辑;在一天执行买入操作,则收益为buy[0] = -prices[0]。
最后的答案就是sell[prices.length-1],因为将所有的股票卖出,才会获得收益,手上没有股票才是最赚钱的。
class Solution {
public int maxProfit(int[] prices, int fee) {
if(prices.length<2){
return 0;
}
int []buy = new int[prices.length];
int []sell = new int[prices.length];
buy[0] = -prices[0];
sell[0] = 0;
for(int i=1;i<prices.length;i++){
buy[i] = Math.max(buy[i-1],sell[i-1] - prices[i]);
sell[i] = Math.max(buy[i-1]+prices[i]-fee,sell[i-1]);
}
return sell[prices.length-1];
}
}
与题目三类似,记录买入与卖出两种状态。
限制条件是最多执行k笔交易,使用二维数组来记录买入和卖出状态,数组的第一维下标i代表当前日期第i天,第二维下标j代表目前已经完成了j笔交易(完成一笔交易的定义是从买入到卖出完成才算一笔交易,只买入未卖出则不算一笔交易)。
其余逻辑与第三题一致,表达式如下:
buy[i][j] = Math.max(buy[i-1][j],sell[i-1][j] - prices[i]);
第i天执行买入操作:buy[第i天][已完成了j笔交易] = Math.max(前一天已持有股票,买入收益与前一天保持一致;前一天没有买入记录,用当前卖出收益减去成本);
sell[i][j] = Math.max(buy[i-1][j-1]+prices[i],sell[i-1][j]);
第i天执行卖出操作:sell[第i天][已完成了j笔交易] = Math.max(前一天的买入收益加上当前的价格;前一天没有买入操作,继续保持前天的卖出收益)。
边界问题,第一天buy[0][0] = -prices[0],sell[0][0] = 0,其余buy[0][j]和sell[0][j]都设置为Integer.MIN_VALUE/2,这样做一是为了将这几个状态设置为不合法,不可能第0天就完成了数笔交易;第二除2是为了在之后的减法操作中防止溢出。
最后的结果是在最后一天的卖出记录中寻找最大值。
class Solution {
public int maxProfit(int k, int[] prices) {
int res = 0;
if(k==0||prices.length==0){
return res;
}
int [][]buy = new int[prices.length][k+1];
int [][]sell = new int[prices.length][k+1];
buy[0][0] = -prices[0];
sell[0][0] = 0;
for(int i=1;i<=k;i++){
sell[0][i] = Integer.MIN_VALUE/2;
buy[0][i] = Integer.MIN_VALUE/2;
}
int n = prices.length;
for(int i =1;i<n;i++){
buy[i][0] = Math.max(buy[i-1][0],sell[i-1][0] - prices[i]);
for(int j=1;j<=k;j++){
buy[i][j] = Math.max(buy[i-1][j],sell[i-1][j] - prices[i]);
sell[i][j] = Math.max(buy[i-1][j-1]+prices[i],sell[i-1][j]);
}
}
for(int i=1;i<=k;i++){
res = Math.max(res,sell[n-1][i]);
}
return res;
}
}
这道题目在写完上面几道题解后顺势完成的。
解题思路和上一题一样,只是将K固定为2.
class Solution {
public int maxProfit(int[] prices) {
if(prices.length<2){
return 0;
}
int [][]buy = new int[prices.length][3];
int [][]sell = new int[prices.length][3];
buy[0][0] = -prices[0];
sell[0][0] = 0;
for(int i=1;i<=2;i++){
buy[0][i]=sell[0][i] = Integer.MIN_VALUE/2;
}
for(int i=1;i<prices.length;i++){
buy[i][0] = Math.max(buy[i-1][0],sell[i-1][0] - prices[i]);
for(int j=1;j<=2;j++){
buy[i][j] = Math.max(buy[i-1][j],sell[i-1][j] -prices[i]);
sell[i][j] = Math.max(buy[i-1][j-1]+prices[i],sell[i-1][j]);
// System.out.println(buy[i][j]+","+sell[i][j]);
}
}
int res = 0;
int max = Math.max(sell[prices.length-1][1],sell[prices.length-1][2]);
res = Math.max(0,max);
return res;
}
}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。