最大子数组和:贪心算法、动态规划和线段树

2022-04-05 18:21:39
贪心算法、动态规划和线段树,求解最大子数组和,解释子数组、子序列和字串的区别。

区分子数组、子序列和字串

项目 子数组 子序列 字串
连续
可以为空

子数组:

贪心算法

适用条件:

动态规划

适用条件:

线段树

关系

例题

53. 最大子数组和
剑指 Offer 42. 连续子数组的最大和

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连续部分。

答案

贪心算法

贪心策略:如果之前和小于 0,舍弃(重置为 0)

var maxSubArray = function(nums) {
  const n = nums.length
  let preSum = r = nums[0]
  for (let i = 1; i < n; i++) {
    if (preSum < 0) preSum = 0
    r = Math.max(r, preSum += nums[i])
  }
  return r
};

动态规划

状态:dp[i] 遍历到 i 元素时的最大和 状态转换:如果 dp[i - 1] 小于 0,舍弃

var maxSubArray = function(nums) {
  const n = nums.length
  const dp = new Int32Array(n)
  dp[0] = nums[0]
  let r = nums[0]
  for (let i = 1; i < n; i++) {
    dp[i] = Math.max(nums[i], dp[i - 1] + nums[i])
    r = Math.max(r, dp[i])
  }
  return r
};

动态规划 · 优化

var maxSubArray = function(nums) {
  const n = nums.length
  let sum = r = nums[0]
  for (let i = 1; i < n; i++) {
    sum = Math.max(nums[i], sum + nums[i])
    r = Math.max(r, sum)
  }
  return r
};
var maxSubArray = function(nums) {
  const n = nums.length
  let sum = r = nums[0]
  for (let i = 1; i < n; i++) {
    if (sum + nums[i] > nums[i]) {
      sum += nums[i]
    } else {
      sum = nums[i]
    }
    if (r < sum) r = sum
  }
  return r
};

线段树

var maxSubArray = function(nums) {
  const d = (l, r) => {
    if (l === r) return new SegmentTreeNode(nums[l], nums[l], nums[l], nums[l])
    const m = l + r >> 1
    const left = d(l, m)
    const right = d(m + 1, r)
    const sum = left.sum + right.sum
    const leftSum = Math.max(left.leftSum, left.sum + right.leftSum)
    const rightSum = Math.max(right.rightSum, right.sum + left.rightSum)
    const maxSum = Math.max(Math.max(left.maxSum, right.maxSum), left.rightSum + right.leftSum)
    return new SegmentTreeNode(sum, leftSum, rightSum, maxSum)
  }
  return d(0, nums.length - 1).maxSum
};
class SegmentTreeNode {
  constructor (sum = 0, leftSum = 0, rightSum = 0, maxSum = 0) {
    this.sum = sum
    this.leftSum = leftSum
    this.rightSum = rightSum
    this.maxSum = maxSum
  }
}