题目描述
这是美团的2016招聘的笔试题。
题目描述
在股市的交易日中,假设最多可进行两次买卖(即买和卖的次数均小于等于2),规则是必须一笔成交后进行另一笔(即买-卖-买-卖的顺序进行)。给出一天中的股票变化序列,请写一个程序计算一天可以获得的最大收益。请采用实践复杂度低的方法实现。
给定价格序列prices及它的长度n,请返回最大收益。保证长度小于等于500。
测试样例:
[10,22,5,75,65,80],6
返回:
87
算法思考
如果是交易一次的话, 也就是先买再卖, 考虑起来会比较简单:
股票最低点买, 最高点卖肯定最赚钱, 但是有时间序列的问题, 差值最大的买入卖出点不一定是股价的最低和最高点。
举例来说:
如果价格序列是 10 20 30 5 , 则利润最大值是20, 10 买入, 30 卖出, 最小点的价格是5, 不在最小点买入
如果价格序列是 10 20 30 5 28,则利润最大值是20, 5 买入, 28 卖出, 最大点的价格是30, 不在最大点卖出
30 10 28 5 20 ,则利润最大值是18, 10 买入, 28 卖出, 最大点的价格是30, 最小点的价格是5,不在最小点买入也不在最大点卖出。
目标是: 后面的价格减去前面价格的差值的最大值。
算法: 将所有的后面价格减去前面价格的情况都列举出来, 找一个最大值, 穷尽所有状况, 一定能找到解。
现在又增加难度, 两次交易, 每次必须先买后卖。
看起来循环的话又增加了一维。而且要控制第一次卖完之后第二次才能买。
灵机一动想到了一个办法, 将价格序列一分为二。
两次交易在两个分开的序列中进行, 找到各自的最大值再加总。
序列拆分时,要确保每个序列都有大于两个的价格, 确保可以买卖
基于此的话, 如果是三次, 四次也可以依次推广。
java实现代码
以下是笔者使用Java实现的代码, 仅供参考:
/**
* @Title: Stock.java
* @Package com.oscar999.algorithm
* @Description: TODO
* @author oscar999
* @date Feb 26, 2018 1:44:57 PM
* @version V1.0
*/
package com.oscar999.algorithm;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @ClassName: Stock
* @Description: TODO
* @author oscar999
*/
public class Stock {
/**
* @Title: main
* @Description: TODO
* @param args
*/
public static void main(String[] args) {
List<Integer> priceList = new ArrayList<Integer>(Arrays.asList(10, 22, 5, 75, 65, 80));
Stock stock = new Stock();
List<Map<String, Integer>> list = stock.getMaxProfixInfo(priceList);
if (list != null && list.size() > 0) {
int maxProfit = 0;
for (int i = 0; i < list.size(); i++) {
Map<String, Integer> map = list.get(i);
if (map.get("profit") != null) {
int iProfit = Integer.valueOf(map.get("profit"));
if (iProfit > 0) {
maxProfit += iProfit;
int ibuy = Integer.valueOf(map.get("buy"));
int isale = Integer.valueOf(map.get("sale"));
System.out.println("Buy: Position=" + (ibuy + 1) + ";Price=" + priceList.get(ibuy));
System.out.println("Sale: Position=" + (isale + 1) + ";Price=" + priceList.get(isale));
}
}
}
System.out.println("Max Profit=" + maxProfit);
} else {
System.out.println("There is some error, can't get max profit.please check.");
}
}
/**
* divice Separate price to two list, get each max , and then count
*
* @Title: getMaxProfixInfo
* @Description: TODO
* @param fPrices
* @return
*/
private List<Map<String, Integer>> getMaxProfixInfo(List<Integer> priceList) {
List<Map<String, Integer>> list = new ArrayList<Map<String, Integer>>();
int iLength = priceList.size();
int maxProfit = 0;
Map<String, Integer> sub1MaxInfoFinal = null;
Map<String, Integer> sub2MaxInfoFinal = null;
for (int iSep = 2; iSep < iLength - 2; iSep++) {
List<Integer> sub1PriceList = priceList.subList(0, iSep);
List<Integer> sub2PriceList = priceList.subList(iSep, iLength);
Map<String, Integer> sub1MaxInfo = getMaxProfixInfoByPrices(sub1PriceList, 0);
Map<String, Integer> sub2MaxInfo = getMaxProfixInfoByPrices(sub2PriceList, iSep);
int subProfit = 0;
int sub1Profit = Integer.valueOf(sub1MaxInfo.get("profit"));
int sub2Profit = Integer.valueOf(sub2MaxInfo.get("profit"));
if (sub1Profit > 0) {
subProfit += sub1Profit;
}
if (sub2Profit > 0) {
subProfit += sub2Profit;
}
if (subProfit > maxProfit) {
maxProfit = subProfit;
if (sub1Profit > 0) {
sub1MaxInfoFinal = sub1MaxInfo;
} else {
sub1MaxInfoFinal = null;
}
if (sub2Profit > 0) {
sub2MaxInfoFinal = sub2MaxInfo;
} else {
sub2MaxInfoFinal = null;
}
}
}
if (sub1MaxInfoFinal != null) {
list.add(sub1MaxInfoFinal);
}
if (sub2MaxInfoFinal != null) {
list.add(sub2MaxInfoFinal);
}
return list;
}
/**
*
* @Title: getMaxProfixInfoByPrices
* @Description: TODO
* @param priceList
* @param iBasePosition
* , sub list postion should add.
* @return
*/
private Map<String, Integer> getMaxProfixInfoByPrices(List<Integer> priceList, int iBasePosition) {
Map<String, Integer> map = null;
if (priceList != null && priceList.size() > 1) {
int iLength = priceList.size();
Integer maxProfit = 0;
int iBuy = 0;
int iSale = 0;
for (int i = 0; i < iLength; i++) {
for (int j = i + 1; j < iLength; j++) {
Integer profit = priceList.get(j) - priceList.get(i);
if (profit > maxProfit) {
maxProfit = profit;
iBuy = i;
iSale = j;
}
}
}
if (maxProfit > 0 && iSale > iBuy) {
map = new HashMap<String, Integer>();
map.put("buy", iBuy + iBasePosition);
map.put("sale", iSale + iBasePosition);
map.put("profit", maxProfit);
}
}
return map;
}
}