53、最大子序和

  1. 题目
    1. 示例:
    2. 进阶:
  • 题解
    1. 1、有条件的累加
    2. 2、动态规划、贪心
    3. 3、分治法
  • 题目

    给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

    示例:

    输入: [-2,1,-3,4,-1,2,1,-5,4],
    输出: 6
    解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
    

    提示:

    • $1 <= nums.length <= 10^5$
    • $10^4 <= nums[i] <= 10^4$

    进阶:

    如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

    链接:https://leetcode-cn.com/problems/maximum-subarray

    题解

    1、有条件的累加

    sum > 0 则一直累加: sum += num
    否则 sum = num

    • 入参:一个数组
    • 初始化最大子序和
    • 初始化临时求和
    • 遍历数组
      • sum > 0
        • 累加
      • 否则 初始化为当前位置的数字值
      • 更新最大字序和
    • 返回最大子序和
    class Solution {
        public int maxSubArray(int[] nums) {
            // 求和,和为负数时,重置sum
            int ans = nums[0];
            int sum = 0;
            for (int num : nums) {
                if (sum > 0) {// 只要sum没有是负数,就继续求和
                    sum += num;
                } else {
                    sum = num;
                }
                // 更新最大值
                ans = Math.max(ans,sum);
            }
            return ans;
        }
    }
    

    2、动态规划、贪心

    class Solution {
      public int maxSubArray(int[] nums) {
        int n = nums.length;
        int currSum = nums[0], maxSum = nums[0];
    
        for(int i = 1; i < n; ++i) {
          currSum = Math.max(nums[i], currSum + nums[i]);// 等价于
          maxSum = Math.max(maxSum, currSum);
        }
        return maxSum;
      }
    }
    
    
    // 链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode/
    
    // 原地算法,实现求和
    class Solution {
      public int maxSubArray(int[] nums) {
        int n = nums.length, maxSum = nums[0];
        for(int i = 1; i < n; ++i) {
          if (nums[i - 1] > 0) nums[i] += nums[i - 1];
          maxSum = Math.max(nums[i], maxSum);
        }
        return maxSum;
      }
    }
    

    3、分治法

    类似二分的归并排序:

    • 去二分值
    • 二分左递归
    • 二分右递归
    • 左右合并,通过累加计算最优子序和,求解
    • 对左边子序列和、右边子序和、合并子序和求最大值,并返回
    class Solution {
      public int crossSum(int[] nums, int left, int right, int p) {
        if (left == right) return nums[left];
        // 计算左侧
        int leftSubsum = Integer.MIN_VALUE;
        int currSum = 0;
        for(int i = p; i > left - 1; --i) {
          currSum += nums[i];
          leftSubsum = Math.max(leftSubsum, currSum);
        }
        // 计算右侧
        int rightSubsum = Integer.MIN_VALUE;
        currSum = 0;
        for(int i = p + 1; i < right + 1; ++i) {
          currSum += nums[i];
          rightSubsum = Math.max(rightSubsum, currSum);
        }
        // 返回两侧的和
        return leftSubsum + rightSubsum;
      }
      // 二分递归
      public int helper(int[] nums, int left, int right) {
        if (left == right) return nums[left];
    
        int p = (left + right) / 2;
    
        int leftSum = helper(nums, left, p);
        int rightSum = helper(nums, p + 1, right);
        // 处理 left 到 right 内的最大连续和,中间值为p
        int crossSum = crossSum(nums, left, right, p);
    
        return Math.max(Math.max(leftSum, rightSum), crossSum);
      }
    
      public int maxSubArray(int[] nums) {
        return helper(nums, 0, nums.length - 1);
      }
    }
    
    // 链接:https://leetcode-cn.com/problems/maximum-subarray/solution/zui-da-zi-xu-he-by-leetcode/
    

    转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1056615746@qq.com

    💰

    Title:53、最大子序和

    Count:682

    Author:攀登

    Created At:2020-07-26, 00:19:44

    Updated At:2024-06-16, 20:52:46

    Url:http://jiafeimao-gjf.github.io/2020/07/26/53%E3%80%81%E6%9C%80%E5%A4%A7%E5%AD%90%E5%BA%8F%E5%92%8C/

    Copyright: 'Attribution-non-commercial-shared in the same way 4.0' Reprint please keep the original link and author.

    ×

    Help us with donation