最大子序列和问题 | 超详细 多解法 原创

195 阅读4分钟

最大子序列和问题 | 超详细 多解法 原创

具体题目参考leetcode第53题

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

子数组 是数组中的一个连续部分。(注意这里的连续是关键点)

1 循环解法

三重循环

  • 很容易想到的是最原始方法------ 暴力三重循环

​ 最外层循环确定序列起始位置,第二层循环确定序列结束位置,第三层循环遍历元素相加,然后判断是否更新最大值.代码简单,不做赘述.

// 三重循环
function maxsub1(a, n) {
  let maxsum = 0;

  for (let i = 0; i < n; i++) {
    for (let j = i; j < n; j++) {
      let currsum = 0;

      for (let k = i; k <= j; k++) {
        currsum += a[k];
      }

      if (currsum > maxsum) {
        maxsum = currsum;
      }
    }
  }

  return maxsum;
}

image-20231114171400221.png

二重循环

  • 略微改进的方法------二重循环

    即向后寻找子序列结束位置时动态计算当前子序列和,并不断比较

// 二重循环
function maxsub2(a, n) {
  let maxsum = 0;

  for (let i = 0; i < n; i++) {
    let currsum = 0;

    for (let j = i; j < n; j++) {
      currsum += a[j];

      if (currsum > maxsum) {
        maxsum = currsum;
      }
    }
  }

  return maxsum;
}

image-20231114171832230.png

一重循环

这里先给出代码,思想和后面的动态规划类似,详细思路可参考后文

function max_subseq(arr) {
  const len = arr.length;
  let maxsum = 0, currsum = 0;
  for (let i = 0; i < len; i++) {
    currsum += arr[i];
    if (currsum > maxsum) {
      maxsum = currsum;
    }
    else if (currsum < 0) {
      currsum = 0;
    }
  }
  return maxsum;
}

2 分治思想

关于分治

  • Divide arguments into groups, until trivial cases found and solve the trivial cases
  • Use recursive steps to get solutions to small groups (分)
  • Use non-recursive steps to combine small group solutions to form the final solution (治)

image-20231114173352833.png

具体而言

  • 对于单个元素而言
    • 他可能处在最大子序列的起始位置,末尾位置,中间位置
  • 对于每一个递归阶段
    • 都是需要分别计算,左序列最大值,右序列最大值,跨越中间元素的序列最大值
    • 然后比较这三者,得到最终最大值
  • 最后递归返回,合并结果(治),得到最大子序列和
// 求最大子序列和

// ,跨越中间元素的序列和最大值
function find_overlap(arr, left, right, mid) {
  let sum1 = 0, sum2 = 0;
  for (let i = mid, tmp = 0; i >= left; i--) {
    tmp += arr[i];
    if (tmp > sum1) sum1 = tmp;
  }
  for (let j = mid + 1, tmp = 0; j <= right; j++) {
    tmp += arr[j];
    if (tmp > sum2) sum2 = tmp;
  }
  return sum1 + sum2;
}

// 辅助函数 求三者最大值
function find_maxOfThree(a, b, c) {
  return ((a > b) ? ((a > c) ? a : c) : ((b > c) ? b : c));
}

// 求最大子序列和
function max_subseq(arr, left, right) {
  // 递归结束条件
  if (left > right) return 0;
  if (left === right) return arr[left];

  const mid = Math.floor((left + right)/2);
  const max_left = max_subseq(arr, left, mid -1);
  const max_right = max_subseq(arr, mid + 1, right);
  const max_mid = find_overlap(arr, left, right, mid);

  return find_maxOfThree(max_left, max_mid, max_right);
}

// 测试用例
const arr = [2, -3, 4, -1, 3, 7, -5];
const res  =max_subseq(arr, 0, arr.length - 1);
console.log(res);

image-20231114173442637.png

3 动态规划

关于动态规划

  • 动态规划的关键点

    • 最优子结构(Optimal Substructure):问题的最优解可以通过其子问题的最优解来构造。换句话说,全局最优解包含了局部最优解。

    • 重叠子问题(Overlapping Subproblems):在递归过程中,不同的子问题可能会多次求解相同的子问题。动态规划通过记忆化或者自底向上的方法来避免重复计算,将子问题的结果保存在表格中。

    • 状态转移方程(State Transition Equation):描述了问题的当前状态和与之相关的子问题之间的关系。状态转移方程是动态规划问题的核心,它定义了如何从已解决的子问题的解构建原问题的解。

  • 动态规划的基本步骤

    • 定义状态(State Definition):明确定义问题的状态,找到问题的子结构。

    • 找到状态转移方程(State Transition Equation):根据问题的最优子结构,找到问题状态之间的转移关系,用数学公式表示。

    • 初始化(Initialization):将问题的最小规模情况下的解初始化,通常是边界情况。

    • 自底向上或自顶向下求解:自底向上是从问题的最小规模开始逐步求解,自顶向下是从问题的最大规模开始逐步递归求解。

    • 优化和空间复杂度分析:优化算法,降低时间和空间复杂度。

具体而言

通过观察归纳我们可以得到以下规律:

  • no subsequence starting with a negative can be the best (minimal) one

负数不可能是目标序列的起始元素

  • if find that sequence i..j is negative, can jump from i to j+1

​ 如果以前一个元素结尾的子序列和小于0,我们可以直接舍弃之前的相加结果,继续从当前元素开始计算

  • 定义状态(子问题)

dp[i]:表示以 nums[i] 结尾连续 子数组的最大和。

  • 状态转移方程

image-20231114175657308.png

image-20231114175513271.png 代码实现 (python版本)

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        size = len(nums)
        if size == 0:
            return 0
        dp = [0 for _ in range(size)]

        dp[0] = nums[0]
        for i in range(1, size):
            if dp[i - 1] >= 0:
                dp[i] = dp[i - 1] + nums[i]
            else:
                dp[i] = nums[i]
        return max(dp)
    
// 复杂度 O(n)

......END ......