力扣Hot100(2)

力扣Hot100

11、最大子数组和

解法一:动态规划(Kadane 算法)
思路
核心思想:遍历数组,维护以当前元素结尾的最大子数组和(变量 pre)。
对于每个位置 i,要么将当前元素 x 加入到之前的子数组中(pre + x),要么以当前元素重新开始一个新的子数组(x)。取两者最大值,即 pre = max(pre + x, x)。
同时维护全局最大和 maxAns,每次更新 pre 后比较取较大值。
最终 maxAns 即为答案。

class Solution {
  public int maxSubArray(int[] nums) {
      int pre = 0;                // pre 表示以当前元素结尾的最大子数组和(初始为0)
      int maxAns = nums[0];       // 全局最大子数组和,初始化为第一个元素(避免数组全负的情况)
      
      for (int x : nums) {        // 遍历每个元素
          // 关键状态转移:要么继续接上前面的子数组,要么从当前元素重新开始
          pre = Math.max(pre + x, x);  
          // 更新全局最大值
          maxAns = Math.max(maxAns, pre);
      }
      return maxAns;
  }
}

复杂度

时间:O(n),一次遍历

空间:O(1)

解法二:分治法(线段树思想)
思路
将数组不断对半分割,直到单个元素。合并时,每个区间需要维护四个信息:

lSum:区间内从左端点开始的最大子数组和(必须包含左端点)

rSum:区间内以右端点结束的最大子数组和(必须包含右端点)

mSum:区间内的最大子数组和(可能完全在左、完全在右、或跨越中点)

iSum:区间内所有元素的总和

合并左右子区间 l 和 r:

iSum = l.iSum + r.iSum

lSum = max(l.lSum, l.iSum + r.lSum) (要么完全在左,要么从左跨到右)

rSum = max(r.rSum, r.iSum + l.rSum)

mSum = max(l.mSum, r.mSum, l.rSum + r.lSum)

最终整个区间的 mSum 即为答案。

class Solution {
    // 内部类,用来存储一个区间上的四个统计值
    public class Status {
        public int lSum, rSum, mSum, iSum;

        public Status(int lSum, int rSum, int mSum, int iSum) {
            this.lSum = lSum;
            this.rSum = rSum;
            this.mSum = mSum;
            this.iSum = iSum;
        }
    }

    // 对外接口:返回整个数组的最大子数组和
    public int maxSubArray(int[] nums) {
        return getInfo(nums, 0, nums.length - 1).mSum;
    }

    // 分治函数:返回区间 [l, r] 的 Status
    public Status getInfo(int[] a, int l, int r) {
        if (l == r) {                                 // 区间只有一个元素
            // 四个值都等于该元素本身
            return new Status(a[l], a[l], a[l], a[l]);
        }
        int m = (l + r) >> 1;                         // 中间位置(右移1位等效除以2)
        Status lSub = getInfo(a, l, m);               // 递归处理左半部分
        Status rSub = getInfo(a, m + 1, r);           // 递归处理右半部分
        return pushUp(lSub, rSub);                    // 合并左右结果
    }

    // 合并两个子区间的 Status
    public Status pushUp(Status l, Status r) {
        // 区间总和 = 左总和 + 右总和
        int iSum = l.iSum + r.iSum;
        
        // 左端点最大子段和:要么完全在左,要么左全加右的 lSum
        int lSum = Math.max(l.lSum, l.iSum + r.lSum);
        
        // 右端点最大子段和:要么完全在右,要么右全加左的 rSum
        int rSum = Math.max(r.rSum, r.iSum + l.rSum);
        
        // 区间最大子段和:max(左最大, 右最大, 左rSum+右lSum)
        int mSum = Math.max(Math.max(l.mSum, r.mSum), l.rSum + r.lSum);
        
        return new Status(lSum, rSum, mSum, iSum);
    }
}

复杂度

时间:O(n),递归树共 2n 个节点,每个节点合并 O(1)

空间:O(log n)(递归栈深度)

注意:分治法虽然比 Kadane 复杂,但可以推广到支持动态修改数组元素的场景(线段树)。

12、合并区间

posted on 2026-04-23 14:45  U~U  阅读(4)  评论(0)    收藏  举报