[Lintcode] Best Time to Buy and Sell Stock I, II, III && Maximum Subarray

买卖股票系列 && Subarray

相关题目:

Best Time to Buy and Sell Stock I && II && III (IV 单独开贴)

Maximum Subarray I && II

为什么这些我要总结到一起呢?因为思路基本一致。

题目简略:

买卖股票1: 一次买卖,利润最大。

买卖股票2: N次买卖,利润最大。

买卖股票3: 2次不重叠的买卖,利润最大。

Maximum Subarray: Given an array of integers, find a contiguous subarray which has the largest sum.

Maximum Subarray II:   两次分割, 求最大sum



不难看出,其实买卖股票1跟Maximum subarray是一个题,所以先来说说这个热身题。

Maximum Subarray:

Given an array of integers, find a contiguous subarray which has the largest sum.

Example

Given the array [−2,2,−3,4,−1,2,1,−5,3], the contiguous subarray [4,−1,2,1] has the largest sum = 6.

Note

The subarray should contain at least one number.

Challenge

Can you do it in time complexity O(n)?

SOLUTION:

最简单的思路,连续子数组有n^2个(开头的位置有n个可能,结尾也有n个可能,一共就是n^2个可能)。两个循环for 头,for尾,可以解决。

再来思考O(n)的方法:

这里已看到Subarray就一定要知道一个概念 prefix sum:前缀和,也就是prefix[i] = sum(A[0]~A[i]). 从prefix sum就可以转化到subarray sum,具体这样实现:

subarray[i, j] = prefix[j] - prefix[i - 1]

既然有这种方法,求最大值也就是说,对于一个固定点来说,找到之前prefix的最小值,就可能找到他们差值的最大值了。

代码:

public class Solution {
    /**
     * @param nums: A list of integers
     * @return: A integer indicate the sum of max subarray
     */
    public int maxSubArray(int[] nums) {
        if (nums == null || nums.length == 0){
            return 0;
        }
        int[] prefix = new int[nums.length + 1];
        prefix[0] = 0;
        int min = Integer.MAX_VALUE;
        int maxSum = Integer.MIN_VALUE;
        for (int i = 1; i <= nums.length; i++){
            prefix[i] = prefix[i - 1] + nums[i - 1];
            min = Math.min(min, prefix[i - 1]);
            maxSum = Math.max(maxSum, prefix[i] - min);
        }
        return maxSum;
    }
}

再来看,买卖股票1:

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.

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

Given an example [3,2,3,1,2], return 1

SOLUTION:

思路完全一样,对于类似这种找两个点的情况,一定要先固定一个点,我们选择固定卖出时机,然后我们再找一个之前的(最小)买入时机,也就可以得到最大利润。

但是每次卖出点向后移动的时候,只需要看移动时产生的可能买入点,能不能更新之前维护的(最小)买入时机就可以,不需要重复遍历

code:

public class Solution {
    /**
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0){
            return 0;
        }
        int min = Integer.MAX_VALUE; // buy timing
        int sum = 0;
        for (int i = 1; i < prices.length; i++){
            min = Math.min(prices[i - 1], min);
            sum = Math.max((prices[i] - min), sum);
        }
        return sum;
    }
}



Follow Up:

Best Time to Buy and Sell Stock II

N次买卖。

这就更简单了,只要发现第二天涨了,就把之前的买的卖了就可以。

code:

class Solution {
    /**
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0){
            return 0;
        }
        int profit = 0;
        for (int i = 1; i < prices.length; i++){
            if (prices[i] > prices[i - 1]){
                profit = profit + prices[i] - prices[i - 1];
            }
        }
        return profit;
    }
};



Follow Up:

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 algorithm to find the maximum profit. You may complete at most two transactions.

Example

Given an example [4,4,6,1,1,4,2,5], return 6.

Note

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

SOLUTION:

这题的难点是,两次买卖,但是两次买卖不能交叉重叠。

采用扫描线方法:模拟一条扫描线,线的左右,分别做一次买卖,使得这次买卖利润最大。

如何实现这个思路呢? 可以开两个数组纪录答案,一个纪录从左边到右边的一次买卖,另一个纪录从右边到左边的一次买卖。left[i] + right[i]就是同一个扫描线的情况下,两边利润和。

因为从做往右维护一个最小点(min)买入点比较方便,而从右往左则是维护一个最大(max)卖出点比较方便,left[]表示在i处卖了股票, right[]表示在i处买了股票的最大值,所以结果是left[i] + right[i] 而不是left[i] + right[i + 1]。

code:

class Solution {
    /**
     * @param prices: Given an integer array
     * @return: Maximum profit
     */
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0){
            return 0;
        }
        int[] left = new int[prices.length];
        int[] right = new int[prices.length];
        int min = Integer.MAX_VALUE;
        //固定买入的点(最小点)
        for (int i = 0; i < prices.length - 1; i++){
            min = Math.min(min, prices[i]);
            left[i + 1] = Math.max((prices[i + 1] - min), left[i]);
        }
        int max = Integer.MIN_VALUE;
        //固定卖出的点(最大点)
        for (int i = prices.length - 1; i > 0; i--){
            max = Math.max(max, prices[i]);
            right[i - 1] = Math.max((max - prices[i - 1]), right[i]);
        }
        int sum = 0;
         //当天卖出再当天买入产生的最大值
        for (int i = 0; i < prices.length; i++){
            sum = Math.max(sum, left[i] + right[i]);
        }
        return sum;
    }
};

Maximum Subarray II (Maximum Subarray I follow up)

Given an array of integers, find two non-overlapping subarrays which have the largest sum.

The number in each subarray should be contiguous.

Return the largest sum.

Example

For given [1, 3, -1, 2, -1, 2], the two subarrays are [1, 3] and [2, -1, 2] or [1, 3, -1, 2] and [2], they both have the largest sum 7.

Note

The subarray should contain at least one number

Challenge

Can you do it in time complexity O(n) ?

SOLUTION:

这题跟上面实际是一样的,处理时候有一点点区别,就是处理right[i]时候,是从右到左的subarray sum,所以最后sum = left[i] + right[i + 1]

public class Solution {
    /**
     * @param nums: A list of integers
     * @return: An integer denotes the sum of max two non-overlapping subarrays
     */
    public int maxTwoSubArrays(ArrayList<Integer> nums) {
        int[] right = new int[nums.size()];
        int[] left = new int[nums.size()];
        int sum = 0;
        int max = Integer.MIN_VALUE;
        int minSum = 0;
        for (int i = 0; i < nums.size(); i++){
            sum = sum + nums.get(i);
            max = Math.max(max, sum - minSum);
            minSum = Math.min(minSum, sum);
            left[i] = max;
        }
        sum = 0;
        minSum = 0;
        max = Integer.MIN_VALUE;
        for (int i = nums.size() - 1; i >= 0; i--){
            sum = sum + nums.get(i);
            max = Math.max(max, sum - minSum);
            minSum = Math.min(minSum, sum);
            right[i] = max;
        }
        max = Integer.MIN_VALUE;
        for (int i = 0; i < nums.size() - 1; i++){
            max = Math.max(max, left[i] + right[i + 1]);
        }
        return max;
    }
}


时间: 2024-10-12 16:20:59

[Lintcode] Best Time to Buy and Sell Stock I, II, III && Maximum Subarray的相关文章

Best Time to Buy and Sell Stock I &amp;&amp; II &amp;&amp; III

题目1: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. If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algori

【LeetCode】 Best Time to Buy and Sell Stock I II III IV 解题报告

Best Time to Buy and Sell Stock I 题意:用一个数组表示股票每天的价格,数组的第i个数表示股票在第i天的价格. 如果只允许进行一次交易,也就是说只允许买一支股票并卖掉,求最大的收益. 分析:动态规划法.从前向后遍历数组,记录当前出现过的最低价格,作为买入价格,并计算以当天价格出售的收益,作为可能的最大收益,整个遍历过程中,出现过的最大收益就是所求. 代码:时间O(n),空间O(1). Best Time to Buy and Sell Stock II 题目:用一

lintcode medium Best Time to Buy and Sell Stock I,II,III

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. If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm

[Leetcode][JAVA] Best Time to Buy and Sell Stock I, II, III

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. If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm

Best Time to Buy and Sell Stock I,II,III [leetcode]

Best Time to Buy and Sell Stock I 只能作一次操作时:维护preMin记录之前出现的最小值 代码如下: int maxProfit(vector<int> &prices) { if (prices.size() == 0) return 0; int profit = 0; int preMin = prices[0]; for (int i = 1; i < prices.size(); i++) { if (prices[i] < pr

leetcode--Best Time to Buy and Sell Stock i ii iii

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. If you were only permitted to complete at most one transaction (ie, buy one and sell one share of the stock), design an algorithm

LeetCode之“动态规划”:Best Time to Buy and Sell Stock I &amp;&amp; II &amp;&amp; III &amp;&amp; IV

1. Best Time to Buy and Sell Stock 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), desi

leetcode day6 -- String to Integer (atoi) &amp;&amp; Best Time to Buy and Sell Stock I II III

1.  String to Integer (atoi) Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases. Notes: It is inte

[Leetcode] Best Time to Buy and Sell Stock I,II,III,IV

三种股票交易算法 一.交易次数没有限制 使用贪心策略,找最长递增序列,同时累加相应利润. 二.只有一次交易 使用动态规划算法,从前往后,依次记记录相应时间节点前面的最小price,同时获得在这个节点的最大利润,同时更新最小price 三.最多两次 使用两次动态规划 1.从左向右,记录在相应的时间节点卖出的最大利润,实际上就是问题二 2.从右向左,记录在相应的时间节点买入的最大利润,因此这里需要记录最大的price. 将each 的left[index]+ right[index]曲最大值. 四.