一、 Best Time to Buy and Sell Stock
eg:只能买卖一次股票,求最大利润
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.
Example 1:
Input: [7, 1, 5, 3, 6, 4]
Output: 5 (6-1 = 5 not 7-1 = 6)
Example 2:
Input: [7, 6, 4, 3, 1]
Output: 0 (no transaction is done)
public static int maxProfit(int[] prices) {
// 暴力递归
int max = Integer.MIN_VALUE;
for(int i = 0; i < prices.length-1; i ++){
for(int j = i + 1; j < prices.length; j ++){
int tmp = prices[j] - prices[i];
max = (tmp > 0 && tmp > max )? tmp : max;
}
}
return max == Integer.MIN_VALUE ? 0 : max;
}
public static int maxProfit(int[] prices){
// Kadane算法
int Cur = 0, max = 0;
for(int i = 1; i < prices.length; i ++){
Cur = Math.max(0, Cur += prices[i] - prices[i-1]);
max = Math.max(Cur, max);
}
return maxSoFar;
}
public static int maxProfit(int[] prices){
if(prices == null || prices.length == 0) return 0;
//两个变量,最低买入价格和当前最高利润,遍历,更新
int buyPrice = prices[0];
int maxProfit = 0;
for(int i = 1; i < prices.length; i++){
buyPrice = Math.min(buyPrice, prices[i]);
maxProfit = Math.max(maxProfit, prices[i] - buyPrice);
}
return maxProfit;
}
二、 Best Time to Buy and Sell Stock 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).
eg:尽可能多的交易来保证利润最大
Q:you must sell the stock before you buy again?
我的理解就是当天同一时间不能卖完再买! 这样可以省掉许多的加法操作。
Example:
1 3 5 6 返回 0 +(6-1)而不是 0 + 3-1 + 5-3 + 6-5(当天卖完又可以买)实际上结果是没有变化的
1 2 3 1 5 返回 3-1 + 5 -1。 当前不能同一时间买卖。
我的理解:
不能在同一天卖出和买入,意思是下次购买前,你必须全部卖出你手上的股票。
1 2 3 :如果1买入,2卖出则不能再2买入,3抛出了,会损失一个利润点。正确的是1买入,3卖出。
另一种考虑:其实只要后面的大于前面的就可以买卖了,典型的贪婪算法。
- 对于贪心来说:可能看似违背题目本意,当天不能购买如 1 3 7,但是反过来想,对于这种单调序列,无论内部多长,取决定性的都是首尾两个元素决定的,完全是等价的。
- 对于非单调序列来说,也是由若干个单调增序列和单调降序列组成的,也是可行的。
(其实这两种算法都能AC = = !!! )
public static int maxProfit(int[] prices){
// 贪婪方法,如果不允许同一天买卖的话,那么就不能应用
int total = 0;
for(int i = 0; i < prices.length - 1; i ++){
if(prices[i + 1] > prices[i]) total += prices[i+1] - prices[i];
}
return total;
}
public static int maxProfit(int[] prices){
//不用贪婪,当两者结果是一样的
int profit = 0, i = 0;
while(i < prices.length){
//找局部最小值
while(i < prices.length - 1 && prices[i + 1] <= prices[i]) i++;
//找到了就开始下一个
int min = prices[i++];
//找写一个局部最大值
while(i < prices.length - 1 && prices[i + 1] >= prices[i]) i++;
profit = profit + (i < prices.length ? prices[i++] - min : 0);
}
return profit;
}
三、 Best Time to Buy and Sell Stock Ⅲ
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.
eg:规定了交易次数只能为2次,该怎么把第一次和第二次的交易联系起来,达到利润最大
常规思路:找个点来分开第一笔和第二笔买卖,类似1中计算各个时间段的第一笔买卖的最大收益,第二笔买卖则是反向的方法 区向前扫描,用out2记录卖出最高价,只能以prices[i]的价格买入,不能用in2来记录最低价,如2 6 1就会出问题
public int maxProfit(int[] prices) {
int len = prices.length;
if (len == 0 || len == 1) return 0;
int in1 = prices[0], out1 = prices[0];
int in2 = prices[len-1], out2 = prices[len-1];
int[] ans1 = new int[len];
int[] ans2 = new int[len];
for (int i = 1, j = len-2; i < len; i++, j--) {
in1 = Math.min(in1, prices[i]);
out1 = Math.max(in1, prices[i]);
ans1[i] = out1-in1>ans1[i-1] ? out1-in1:ans1[i-1];
in2 = prices[j];
ans2[j] = out2-in2>ans2[j+1] ? out2-in2:ans2[j+1];
out2 = Math.max(out2, prices[j]);
}
int ans = Math.max(ans1[len-1], ans2[0]);
for (int i = 1; i < len-1; i++) {
ans = Math.max(ans1[i]+ans2[i+1], ans);
}
return ans;
}
最优方法: DP
buy1[i] = max( - prices[i], buy1[i - 1])
sell1[i] = max(buy1[i - 1] + price[i], sell1[i - 1])
buy2[i] = max( sell1[i -1] - prices[i], buy2[i - 1])
sell2[i] = max(buy2[i - 1] + price[i], sell2[i - 1])
public static int maxProfit(int[] prices){
int sell1 = 0, sell2 = 0;
int buy1 = Integer.MIN_VALUE, buy2 = Integer.MIN_VALUE;
for(int i = 0; i < prices.length; i ++){
buy1 = Math.max(buy1, - prices[i]);
sell1 = Math.max(sell1, buy1 + prices[i]);
buy2 = Math.max(buy2, sell1 - prices[i]);
sell2 = Math.max(sell2, buy2 + prices[i]);
}
return sell2;
}