Best Time to Buy and Sell Stock
给定n天的股票价格,最多只能做一次交易求最大收益。我们保留价格中的最小值,之后只要比较卖了它能得到的最大收益。
public int maxProfit(int[] prices) {
if (prices == null || prices.length == 0) {
return 0;
}
int min = Integer.MAX_VALUE; //just remember the smallest price
int profit = 0;
for (int i : prices) {
min = i < min ? i : min;
profit = (i - min) > profit ? i - min : profit;
}
return profit;
}
Best Time to Buy and Sell Stock II
给定n天的股票价格,不限次数交易求最大收益。这道题与上道题不同于不限交易次数,如此我们之前后面价格高就进行一次操作就可。
public int maxProfit(int[] prices) {
int profit = 0;
for (int i = 0; i < prices.length - 1; i++) {
int diff = prices[i+1] - prices[i];
if (diff > 0) {
profit += diff;
}
}
return profit;
}
Best Time to Buy and Sell Stock III
这道题是最多可进行两次操作。那么从左向右递归再从右向左递归,最后求可以加成的和最大。
public int maxProfit(int[] prices) {
if (prices == null || prices.length <= 1) {
return 0;
}
int[] left = new int[prices.length];
int[] right = new int[prices.length];
// DP from left to right;
left[0] = 0;
int min = prices[0];
for (int i = 1; i < prices.length; i++) {
min = Math.min(prices[i], min);
left[i] = Math.max(left[i - 1], prices[i] - min);
}
//DP from right to left;
right[prices.length - 1] = 0;
int max = prices[prices.length - 1];
for (int i = prices.length - 2; i >= 0; i--) {
max = Math.max(prices[i], max);
right[i] = Math.max(right[i + 1], max - prices[i]);
}
int profit = 0;
for (int i = 0; i < prices.length; i++){
profit = Math.max(left[i] + right[i], profit);
}
return profit;
}
Best Time to Buy and Sell Stock IV
这道题为最多只能进行k次交易。所以使用动规方法就好。
public int maxProfit(int k, int[] prices) {
// write your code here
if (k == 0) {
return 0;
}
if (k >= prices.length / 2) {
int profit = 0;
for (int i = 1; i < prices.length; i++) {
if (prices[i] > prices[i - 1]) {
profit += prices[i] - prices[i - 1];
}
}
return profit;
}
int n = prices.length;
int[][] mustsell = new int[n + 1][n + 1]; // mustSell[i][j] 表示前i天,至多进行j次交易,第i天必须sell的最大获益
int[][] globalbest = new int[n + 1][n + 1]; // globalbest[i][j] 表示前i天,至多进行j次交易,第i天可以不sell的最大获益
mustsell[0][0] = globalbest[0][0] = 0;
for (int i = 1; i <= k; i++) {
mustsell[0][i] = globalbest[0][i] = 0;
}
for (int i = 1; i < n; i++) {
int gainorlose = prices[i] - prices[i - 1];
mustsell[i][0] = 0;
for (int j = 1; j <= k; j++) {
mustsell[i][j] = Math.max(globalbest[(i - 1)][j - 1] + gainorlose,
mustsell[(i - 1)][j] + gainorlose);
globalbest[i][j] = Math.max(globalbest[(i - 1)][j], mustsell[i ][j]);
}
}
return globalbest[(n - 1)][k];
}
Maximum Subarray
求一个数组的最大子数组。这道题有多种解法,这里只给出一种,考虑子数组的开头一定不会是负数(如果是负数不取该数可以获得一个和更大的子数组)。
public int maxSubArray(int[] A) {
if (A == null || A.length == 0){
return 0;
}
int max = Integer.MIN_VALUE, sum = 0;
for (int i = 0; i < A.length; i++) {
sum += A[i];
max = Math.max(max, sum);
sum = Math.max(sum, 0);
}
return max;
}
Maximum Subarray II
这道题为求两个子数组。类似于Best Time to Buy and Sell Stock III的最多可以进行两次交易。进行两次动规,取最大的和。
public int maxTwoSubArrays(ArrayList<Integer> nums) {
// write your code
int size = nums.size();
int[] left = new int[size];
int[] right = new int[size];
int sum = 0;
int minSum = 0;
int max = Integer.MIN_VALUE;
for(int i = 0; i < size; i++){
sum += nums.get(i);
max = Math.max(max, sum - minSum);
minSum = Math.min(sum, minSum);
left[i] = max;
}
sum = 0;
minSum = 0;
max = Integer.MIN_VALUE;
for(int i = size - 1; i >= 0; i--){
sum += nums.get(i);
max = Math.max(max, sum - minSum);
minSum = Math.min(sum, minSum);
right[i] = max;
}
max = Integer.MIN_VALUE;
for(int i = 0; i < size - 1; i++){
max = Math.max(max, left[i] + right[i + 1]);
}
return max;
}
Maximum Subarray III
这道题求k个子数组。也是与Best Time to Buy and Sell Stock IV相类似,localMax[i][j]表示nums[j-1]一定在最后所取得子数组中,而globalMax[i - 1][j-1]可以不包含。
public int maxSubArray(int[] nums, int k) {
if (nums.length < k) {
return 0;
}
int len = nums.length;
int[][] globalMax = new int[k + 1][len + 1];
int[][] localMax = new int[k + 1][len + 1];
for (int i = 1; i <= k; i++) {
localMax[i][i-1] = Integer.MIN_VALUE;
//小于 i 的数组不能够partition
for (int j = i; j <= len; j++) {
localMax[i][j] = Math.max(localMax[i][j-1], globalMax[i - 1][j-1]) + nums[j-1];
if (j == i)
globalMax[i][j] = localMax[i][j];
else
globalMax[i][j] = Math.max(globalMax[i][j-1], localMax[i][j]);
}
}
return globalMax[k][len];
}