最大子数组问题和kadane算法

最大子数组问题及其历史

20世纪70年代末,瑞典数学家ulf grenander一直在讨论一个问题:如何比暴力破解更有效地分析二维图像数据数组?那时的计算机速度很慢,图片相对于 ram 来说也很大。更糟糕的是,在最坏的情况下,暴力破解需要 o(n^6) 时间(六次时间复杂度)。

首先,grenandier 简化了问题:给定一个一维数字数组,如何最有效地找到总和最大的连续子数组?

最大子数组问题和kadane算法

蛮力:一种具有立方时间复杂度的简单方法

蛮力,分析一维数组的时间是分析二维数组的一半,所以 o(n^3) 来检查每个可能的组合(立方时间复杂度)。

def max_subarray_brute_force(arr):    max_sum = arr[0] # assumes arr has a length    # iterate over all possible subarrays    for i in range(len(arr)):        for j in range(i, len(arr)):            current_sum = 0            # sum the elements of the subarray arr[i:j+1]            for k in range(i, j + 1):                current_sum += arr[k]            # update max_sum if the current sum is greater            max_sum = max(max_sum, current_sum)    return max_sumprint(max_subarray_brute_force([-2, -3, 4, -1, -2, 1, 5, -3]), "== 7")

grenander 的 o(n²) 优化:向前迈出了一步

grenander 将其改进为 o(n^2) 解决方案。我在研究中找不到他的代码,但我的猜测是他只是摆脱了最内层的循环,该循环将两个索引之间的所有数字相加。相反,我们可以在迭代子数组时保留运行总和,从而将循环次数从三个减少到两个。

def max_subarray_optimized(arr):    max_sum = arr[0]  # assumes arr has a length    # iterate over all possible starting points of the subarray    for i in range(len(arr)):        current_sum = 0        # sum the elements of the subarray starting from arr[i]        for j in range(i, len(arr)):            current_sum += arr[j]            # update max_sum if the current sum is greater            max_sum = max(max_sum, current_sum)    return max_sum

shamos 的分而治之:将问题分解为 o(n log n)

grenander 向计算机科学家 michael shamos 展示了这个问题。 shamos思考了一晚上,想出了一个分而治之的方法,o(n log n)。

真是太聪明了。想法是将数组分成两半,然后递归地找到每一半的最大子数组和以及穿过中点的子数组。

def max_crossing_sum(arr, left, mid, right):    # left of mid    left_sum = float('-inf')    current_sum = 0    for i in range(mid, left - 1, -1):        current_sum += arr[i]        left_sum = max(left_sum, current_sum)    # right of mid    right_sum = float('inf')    current_sum = 0    for i in range(mid + 1, right + 1):        current_sum += arr[i]        right_sum = max(right_sum, current_sum)    # sum of elements on the left and right of mid, which is the maximum sum that crosses the midpoint    return left_sum + right_sumdef max_subarray_divide_and_conquer(arr, left, right):    # base case: only one element    if left == right:        return arr[left]    # find the midpoint    mid = (left + right) // 2    # recursively find the maximum subarray sum for the left and right halves    left_sum = max_subarray_divide_and_conquer(arr, left, mid)    right_sum = max_subarray_divide_and_conquer(arr, mid + 1, right)    cross_sum = max_crossing_sum(arr, left, mid, right)    # return the maximum of the three possible cases    return max(left_sum, right_sum, cross_sum)def max_subarray(arr):    return max_subarray_divide_and_conquer(arr, 0, len(arr) - 1)print(max_subarray([-2, -3, 4, -1, -2, 1, 5, -3]), "== 7")

这将时间复杂度降低到 o(nlogn) 时间,因为首先将数组分为两半 (o(logn)),然后找到最大交叉子数组需要 o(n)

kadane 算法:优雅的 o(n) 解决方案

统计学家 jay kadane 看了代码,立即发现 shamos 的解决方案未能使用邻接约束作为解决方案的一部分。

这是他意识到的

-如果数组只有负数,那么答案将始终是数组中最大的数字,假设我们不允许空子数组。

-如果数组只有正数,答案总是将整个数组相加。

-如果你有一个同时包含正数和负数的数组,那么你可以一步步遍历该数组。如果在任何时候您正在查看的数字大于其之前的所有数字的总和,则解决方案不能包含任何先前的数字。因此,您从当前数字开始一个新的总和,同时跟踪迄今为止遇到的最大总和。

maxSubArray(nums):    # avoiding type errors or index out of bounds errors    if nums is None or len(nums) == 0:        return 0    max_sum = nums[0]  # max sum can't be smaller than any given element    curr_sum = 0    # Kadane's algorithm    for num in nums:        curr_sum = max(num, curr_sum + num)        max_sum = max(curr_sum, max_sum)    return max_sum

我喜欢这个算法的原因是它可以应用于许多其他问题。尝试调整它来解决这些 leetcode 问题:

一和零
圆形子数组的最大和
最小子数组总和
最大升序子数组和
最大产品子数组
连续子数组和
最大交替和子数组(高级)
矩形的最大和不大于 k

以上就是最大子数组问题和kadane算法的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/1348963.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年12月13日 12:28:17
下一篇 2025年12月13日 12:28:33

相关推荐

  • 代码气味 – 蹲着

    不要提前在关键任务资源上使用可猜测的名称 tl;dr:通过避免可预测的命名模式来保护您的云资源。 问题 可预测的名字 未经授权的访问 数据暴露风险 影子资源 帐户接管 idor 漏洞 过早优化 解决方案 使用带有暗键的独特存储桶名称 验证创建的所有权 充分保障资源 间接混淆真实姓名 书名防止抢注 随…

    好文分享 2025年12月13日
    000
  • 避免条件语句的智慧

    循环复杂度是衡量代码复杂性和混乱程度的指标。 高圈复杂度并不是一件好事,恰恰相反。 简单来说,圈复杂度与程序中可能的执行路径的数量成正比。换句话说,圈复杂度和条件语句的总数(尤其是它们的嵌套)密切相关。 所以今天我们来谈谈条件语句。 反如果 2007年,francesco cirillo发起了一场名…

    2025年12月13日
    000
  • Django AllAuth 章 使用自定义字段扩展 Django AllAuth 用户模型

    注意:本文最初发布在我的 substack 上,网址为 https://andresalvareziglesias.substack.com/ 这是 django allauth 系列文章的最后一章。在这五章中,我们发现了一个小奇迹,一个非常有用的 django 组件来处理我们所有的身份验证需求。在…

    2025年12月13日
    000
  • 如何使用 Ollama 和 LangChain 创建本地 RAG 代理

    什么是 rag? rag 代表检索增强生成,这是一种强大的技术,旨在通过以文档形式为大型语言模型(llm)提供特定的相关上下文来增强其性能。与纯粹根据预先训练的知识生成响应的传统法学硕士不同,rag 允许您通过检索和利用实时数据或特定领域的信息,使模型的输出与您期望的结果更紧密地结合起来。 rag …

    2025年12月13日
    000
  • 如何构建简单的 AI 代理:分步指南

    人工智能无处不在,从回答您问题的聊天机器人到管理您日程安排的智能助手。但您是否知道只需几步即可构建自己的人工智能代理?无论您是开发人员还是好奇的爱好者,本指南都将向您展示如何创建一个可以执行基本任务的简单 ai 代理,同时让事情变得有趣和简单。 ? ?️ 第 1 步:定义 ai 代理的使命 首先,决…

    2025年12月13日
    000
  • 释放 Python 脚本的力量:日复一日的 DevOps 工具系列

    欢迎来到“50 天 50 个 devops 工具”系列的第 28 天!今天,我们将深入探讨 python 脚本世界——这是任何 devops 专业人员的一项关键技能。 python 以其简单性、可读性和广泛的库支持而闻名,已成为自动化任务、管理基础设施和开发可扩展应用程序的重要工具。 为什么 pyt…

    2025年12月13日
    000
  • 使用 Diffuser 运行 Fluxn Mac

    什么是扩散器? 拥抱脸 / 扩散器 ? diffusers:最先进的扩散模型,用于 pytorch 和 flax 中的图像和音频生成。 ? diffusers 是最先进的预训练扩散模型的首选库,用于生成图像、音频甚至分子的 3d 结构。无论您是在寻找简单的推理解决方案还是训练自己的扩散模型,? di…

    2025年12月13日 好文分享
    000
  • 使用 Asyncio 创建和管理任务

    asyncio 允许开发者轻松地用 python 编写异步程序。该模块还提供了多种异步任务的方法,并且由于执行方法多种多样,因此可能会让人困惑于使用哪一种。 在本文中,我们将讨论使用 asyncio 创建和管理任务的多种方法。 什么是异步任务? 在 asyncio 中,task 是一个包装协程并安排…

    2025年12月13日
    000
  • BigQuery 和 XGBoost 集成:用于二元分类的 Jupyter Notebook 教程

    介绍 在为表格数据选择二元分类模型时,我决定快速尝试一种快速的非深度学习模型:梯度提升决策树(gbdt)。本文介绍了使用 bigquery 作为数据源并使用 xgboost 算法进行建模来创建 jupyter notebook 脚本的过程。 完整脚本 对于那些喜欢直接跳入脚本而不进行解释的人,这里是…

    2025年12月13日
    000
  • 了解 Python 中常规类和数据类之间的差异

    介绍 在python中定义数据结构可以通过各种方法来完成。两种常用的方法是常规类和数据类。了解这两种方法之间的差异有助于为给定任务选择最合适的选项。本文对常规类和数据类进行了比较分析,强调了它们各自的特点和适当的用例。 常规课程 python 中的常规类是创建对象的传统方式。它需要对各种方法和属性进…

    2025年12月13日
    000
  • 如何在 django 模型的 save 方法中获取当前用户?

    如何在 django 模型的 save 方法中获取当前用户? 八月 11 ’24 评论:1 答案:0 0 我有以下 django 模型: class Listing(models.Model) STATUS_CHOICES = [ (‘available’, ‘Available’), …

    2025年12月13日
    000
  • 关于如何使用 pip 安装你需要知道的一切

    在本文中,我们正在研究使用 pip 将代码安装到虚拟环境中的不同方法。 这些会变得更加复杂,但不用担心,我会全程陪伴您。 拍拍你的背 废话说够了!让我们从简单的事情开始吧。 安装本地存储库 假设以下情况:您刚刚签出了存储库并想要安装需求。 这可以通过使用以下命令轻松完成……当…

    2025年12月13日
    000
  • 在深入了解 Nylas 之前需要了解的关键概念

    在深入研究 nylas 之前必须了解的概念 所以,我已经准备好开始使用 nylas 及其强大的 api,但在开始之前,值得花点时间确保我很好地掌握了一些基本概念。这些构建块不仅可以帮助我有效地使用 nylas,还可以使我的开发过程更加顺利和安全。 1.python虚拟环境:保持整洁 让我们从pyth…

    2025年12月13日
    000
  • Python-文件

    文件操作: 文件读取文件写入追加内容 文件读取:以 open(‘logs.txt’, ‘r’) 作为文件: open是python内置函数,用于打开文件。第一个参数是文件名,第二个参数是读取模式。with语句用于自动关闭文件。这将防止内存泄漏,提供更好…

    2025年12月13日
    000
  • 使用 AWS 学习 Python – 第 2 天

    虚拟环境 今天我们将学习虚拟环境。 python 中的虚拟环境是一个容器,所有代码和其他 python 包都驻留在其中。它允许您将 python 配置与系统上的其他版本分开。开发 python 代码时始终使用虚拟环境是一个好主意。 要创建虚拟环境,我们将使用以下命令: python -m venv …

    2025年12月13日
    000
  • Python 库初学者指南

    python 以其简单性和多功能性而闻名,使其成为初学者和专业人士的热门选择。 python 最强大的功能之一是其广泛的库集合。这些库是预先编写的代码的集合,您可以使用它们来执行常见任务,从而节省您的时间和精力。在这篇博客中,我们将探索每个初学者都应该知道的一些基本 python 库。 1.什么是p…

    2025年12月13日
    000
  • 自动化共同基金 CAS 解析器、导入和分析

    自动化共同基金 CAS 导入和分析:分步指南 管理共同基金投资可能是一项复杂的任务,尤其是在处理多个客户和大量数据时。为了简化此流程,我创建了一个工作流程,可自动导入和分析共同基金的合并账户报表 (CAS)。本博客将引导您完成从接收 CAS 到分析和呈现数据的工作流程。 1. 客户端转发CAS给支持…

    2025年12月13日
    000
  • tea-tasting:用于 A/B 测试统计分析的 Python 包

    简介 我开发了tea-tasting,一个用于 a/b 测试统计分析的 python 包,具有​​: 学生的 t 检验、bootstrap、cuped 方差缩减、功效分析以及其他开箱即用的统计方法和方法。支持广泛的数据后端,例如 bigquery、clickhouse、postgresql/gree…

    2025年12月13日
    000
  • Python – 字典、集合、元组

    这三个都是python中不同类型的数据结构。这用于存储不同的数据集合。根据我们要求的用例,我们需要在其中进行选择。 字典(dict): 字典是键值对的集合,其中每个键与一个值关联可以根据键值检索数据(基于键的搜索),因为键要求是唯一的。字典在 3.7 之前都是无序的,值可以更改。密钥名称不能直接更改…

    2025年12月13日
    000
  • 精通编码之路初学者指南

    您已经掌握了编码的基础知识。循环、函数,甚至简单的网站都在你的掌握之中。 但是从休闲程序员转变为专业程序员需要什么? 好吧,我在这里帮助正在寻找相同东西的初学者。 让我们潜入吧。 专业心态:不仅仅是代码 解决问题 编码既是关于编写代码,也是关于解决问题。将复杂的问题分解为更小的、可管理的步骤至关重要…

    2025年12月13日
    000

发表回复

登录后才能评论
关注微信