LeetCode第53题:最大子数组和【python 5种算法】

简介: LeetCode第53题:最大子数组和【python 5种算法】

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。

会一些的技术:数据分析、算法、SQL、大数据相关、python

欢迎加入社区:码上找工作

作者专栏每日更新:

LeetCode解锁1000题: 打怪升级之旅

python数据分析可视化:企业实战案例

题目描述

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

输入格式
  • nums:一个整数数组。
输出格式
  • 返回整数,表示最大子数组的和。

示例

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

方法一:动态规划

解题步骤
  1. 定义状态dp[i] 表示以 nums[i] 结尾的最大子数组和。
  2. 状态转移dp[i] = max(nums[i], dp[i-1] + nums[i]),意味着当前元素单独成数组或加入前面的数组。
  3. 初始化dp[0] = nums[0],只有一个元素时最大和即为该元素。
  4. 遍历数组:根据状态转移方程更新 dp 数组。
  5. 得到结果:返回 dp 数组中的最大值,即为所求。
完整的规范代码
def maxSubArray(nums):
    """
    动态规划解法求最大子数组和
    :param nums: List[int], 输入的整数数组
    :return: int, 最大子数组的和
    """
    if not nums:
        return 0
    
    n = len(nums)
    dp = nums[0]
    max_sum = dp
    for i in range(1, n):
        dp = max(nums[i], dp + nums[i])
        if dp > max_sum:
            max_sum = dp
    return max_sum
# 示例调用
print(maxSubArray([-2,1,-3,4,-1,2,1,-5,4]))  # 输出: 6
算法分析
  • 时间复杂度:(O(n)),其中 n 是数组 nums 的长度,我们只需要遍历一次数组。
  • 空间复杂度:(O(1)),使用了常数空间存储 dp 状态和结果。

方法二:分治法

解题步骤
  1. 分治思想:将数组分成左右两部分,分别求左右部分的最大子数组和,以及跨越中点的最大子数组和。
  2. 递归求解:递归地对左右两部分数组应用分治法,直到数组长度为1。
  3. 合并结果:最大子数组和可能在左侧、右侧或跨越中心,取这三者的最大值。
完整的规范代码
def maxSubArray(nums):
    """
    分治法解决最大子数组和问题
    :param nums: List[int], 输入的整数数组
    :return: int, 最大子数组的和
    """
    def maxSubArrayDivideAndConquer(l, r):
        if l == r:
            return nums[l]
        mid = (l + r) // 2
        left_max = maxSubArrayDivideAndConquer(l, mid)
        right_max = maxSubArrayDivideAndConquer(mid + 1, r)
        
        max_left_border_sum = nums[mid]
        max_right_border_sum = nums[mid + 1]
        tmp = 0
        for i in range(mid, l - 1, -1):
            tmp += nums[i]
            if tmp > max_left_border_sum:
                max_left_border_sum = tmp
        
        tmp = 0
        for i in range(mid + 1, r + 1):
            tmp += nums[i]
            if tmp > max_right_border_sum:
                max_right_border_sum = tmp
        
        return max(left_max, right_max, max_left_border_sum + max_right_border_sum)
    
    return maxSubArrayDivideAndConquer(0, len(nums) - 1)
# 示例调用
print(maxSubArray([-2,1,-3,4,-1,2,1,-5,4]))  # 输出: 6
算法分析
  • 时间复杂度:(O(n \log n)),递归的每层需要 (O(n)) 的时间合并结果,共有 (\log n) 层。
  • 空间复杂度:(O(\log n)),递归栈的深度。

方法三:贪心算法

解题步骤
  1. 初始化变量:设置两个变量,current_sum 表示当前遍历到的子数组的和,max_sum 用来存储遍历过程中遇到的最大子数组和。
  2. 遍历数组:对数组中的每个元素进行遍历,根据贪心策略更新 current_summax_sum
  3. 更新当前和:如果 current_sum 小于0,就重新设置 current_sum 为当前元素,否则就累加当前元素。
  4. 更新最大和:每步都取 current_summax_sum 的较大值更新 max_sum
完整的规范代码
def maxSubArray(nums):
    """
    使用贪心算法计算最大子数组和
    :param nums: List[int], 输入的整数数组
    :return: int, 最大子数组的和
    """
    current_sum = max_sum = nums[0]
    for num in nums[1:]:
        current_sum = max(num, current_sum + num)
        max_sum = max(max_sum, current_sum)
    return max_sum
# 示例调用
print(maxSubArray([-2,1,-3,4,-1,2,1,-5,4]))  # 输出: 6
算法分析
  • 时间复杂度:(O(n)),其中 n 是数组 nums 的长度,因为我们只需遍历一次数组。
  • 空间复杂度:(O(1)),使用了常数额外空间。

方法四:改进的动态规划(空间优化)

解题步骤
  1. 初始化变量:与标准动态规划方法相似,但只用一个变量来存储上一个状态的 dp 值,从而减少空间使用。
  2. 遍历更新:遍历数组,根据 dp[i-1] 更新 dp[i]
  3. 记录最大和:在遍历过程中持续更新最大子数组和。
完整的规范代码
def maxSubArray(nums):
    """
    使用改进的动态规划算法(空间优化版本)求最大子数组和
    :param nums: List[int], 输入的整数数组
    :return: int, 最大子数组的和
    """
    n = len(nums)
    current = max_sum = nums[0]
    for i in range(1, n):
        current = max(nums[i], current + nums[i])
        max_sum = max(max_sum, current)
    return max_sum
# 示例调用
print(maxSubArray([-2,1,-3,4,-1,2,1,-5,4]))  # 输出: 6
算法分析
  • 时间复杂度:(O(n)),只需遍历数组一次。
  • 空间复杂度:(O(1)),不使用额外的空间除了几个必要变量。

方法五:分块累计法

解题步骤
  1. 分块累计:采用分块的方式累计子数组和,每当累计和小于0时重新开始计算。
  2. 遍历数组:在遍历过程中,对每个分块的和进行计算,并更新全局最大和。
完整的规范代码
def maxSubArray(nums):
    """
    使用分块累计法求最大子数组和
    :param nums: List[int], 输入的整数数组
    :return: int, 最大子数组的和
    """
    max_sum = nums[0]
    current_sum = 0
    for num in nums:
        current_sum += num
        if current_sum > max_sum:
            max_sum = current_sum
        if current_sum < 0:
            current_sum = 0
    return max_sum
# 示例调用
print(maxSubArray([-2,1,-3,4,-1,2,1,-5,4]))  # 输出: 6
算法分析
  • 时间复杂度:(O(n)),遍历一次数组。
  • 空间复杂度:(O(1)),仅使用固定空间。

不同算法的优劣势对比

特征 方法一: 动态规划 方法二: 贪心算法 方法三: 分治法 方法四: 改进动态规划 方法五: 分块累计法
时间复杂度 (O(n)) (O(n)) (O(n log n)) (O(n)) (O(n))
空间复杂度 (O(1)) (O(1)) (O(log n)) (O(1)) (O(1))
优势 - 基本且直观 - 实现简单 - 适合并行处理 - 空间高效 - 直观易懂
劣势 - 无显著劣势 - 需要理解逻辑 - 较慢 - 与方法一类似 - 与贪心相似

应用示例

金融分析

在金螌数据分析中,最大子数组和可以用来确定股票的最优买卖时期,即找出股价变动中的最大盈利窗口。

信号处理

在处理信号时,寻找最大子数组和可以用来检测一段时间内的最大信号强度,有助于从噪声中提取有用信号。


欢迎关注微信公众号 数据分析螺丝钉

相关文章
|
1月前
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
38 0
|
11天前
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
|
1月前
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
23 2
|
1月前
【LeetCode-每日一题】 删除排序数组中的重复项
【LeetCode-每日一题】 删除排序数组中的重复项
19 4
|
1月前
|
索引
Leetcode第三十三题(搜索旋转排序数组)
这篇文章介绍了解决LeetCode第33题“搜索旋转排序数组”的方法,该问题要求在旋转过的升序数组中找到给定目标值的索引,如果存在则返回索引,否则返回-1,文章提供了一个时间复杂度为O(logn)的二分搜索算法实现。
18 0
Leetcode第三十三题(搜索旋转排序数组)
|
1月前
|
算法 C++
Leetcode第53题(最大子数组和)
这篇文章介绍了LeetCode第53题“最大子数组和”的动态规划解法,提供了详细的状态转移方程和C++代码实现,并讨论了其他算法如贪心、分治、改进动态规划和分块累计法。
57 0
|
1月前
|
C++
【LeetCode 12】349.两个数组的交集
【LeetCode 12】349.两个数组的交集
16 0
|
26天前
|
算法 安全 数据安全/隐私保护
基于game-based算法的动态频谱访问matlab仿真
本算法展示了在认知无线电网络中,通过游戏理论优化动态频谱访问,提高频谱利用率和物理层安全性。程序运行效果包括负载因子、传输功率、信噪比对用户效用和保密率的影响分析。软件版本:Matlab 2022a。完整代码包含详细中文注释和操作视频。
|
11天前
|
算法 数据挖掘 数据安全/隐私保护
基于FCM模糊聚类算法的图像分割matlab仿真
本项目展示了基于模糊C均值(FCM)算法的图像分割技术。算法运行效果良好,无水印。使用MATLAB 2022a开发,提供完整代码及中文注释,附带操作步骤视频。FCM算法通过隶属度矩阵和聚类中心矩阵实现图像分割,适用于灰度和彩色图像,广泛应用于医学影像、遥感图像等领域。
|
12天前
|
算法 调度
基于遗传模拟退火混合优化算法的车间作业最优调度matlab仿真,输出甘特图
车间作业调度问题(JSSP)通过遗传算法(GA)和模拟退火算法(SA)优化多个作业在并行工作中心上的加工顺序和时间,以最小化总完成时间和机器闲置时间。MATLAB2022a版本运行测试,展示了有效性和可行性。核心程序采用作业列表表示法,结合遗传操作和模拟退火过程,提高算法性能。