LeetCode刷题系列(十四)Sell Stock && Maximum SubArrays

本文解析了四种不同约束条件下的股票买卖最佳时机算法:仅能进行一次交易、不限次数交易、最多两次交易及最多进行k次交易的情况,并介绍了求解最大子数组及其变种问题的算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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];
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值