编程题-最大子数组和(中等-重点【贪心、动态规划、分治思想的应用】)
题目:
给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组是数组中的一个连续部分。

解法一(枚举法-时间复杂度超限):
暴力法,nums的数组元素被重复访问多次,导致时间复杂度超限,仅作为与下面两种方法的对比参考,并不是本题的正确解,时间复杂度为O(n^2)超限,如下为实现代码:
class Solution{
public:int maxSubArray(vector<int> &nums){//类似寻找最大最小值的题目,初始值一定要定义成理论上的最小最大值int max = INT_MIN;int numsSize = int(nums.size());for (int i = 0; i < numsSize; i++){ int sum = 0;for (int j = i; j < numsSize; j++){ sum += nums[j];if (sum > max){max = sum;}}}return max;}
};
解法二(动态规划):
假设nums数组的长度是n,下标从0到n-1。我们用f(i)代表以第i个数结尾的【连续子数组的最大和】,很显然我们要求的答案就是:max(0≤i≤n-1){f(i)}。
因此我们只需要求出每个位置的f(i),然后返回f数组中的最大值即可。那么我们如何求f(i)呢?我们可以考虑nums[i]单独成为一段还是加入f(i-1)对应的那一段,这取决于nums[i]和f(i-1)+nums[i]的大小,我们希望获得一个比较大的,于是可以写出动态规划转移方程:
于是我们可以只用一个变量pre来维护对于当前f(i)的f(i-1)的值是多少。
如果编号为 i 的子问题的结果是负数或者 0 ,那么编号为 i + 1 的子问题就可以把编号为 i 的子问题的结果舍弃掉,而子问题的定义必须以一个数结尾,因此如果子问题 i 的结果是负数或者 0,那么子问题 i + 1 的答案就是以 nums[i] 结尾的那个数。题目只要求返回结果,不要求得到最大的连续子数组是哪一个。这样的问题通常可以使用「动态规划或者贪心算法」解决。如下为实现代码:
class Solution {
public:int maxSubArray(vector<int>& nums) {//pre表示当前f(i)下的f(i-1)的值,初始时pre为0,//maxAns为截止至第i个索引元素时,最大的子数组和,最终的返回值int pre = 0, maxAns = nums[0];for (const auto &x: nums) {pre = max(pre + x, x);maxAns = max(maxAns, pre);}return maxAns;}
};
解法三(分治思想):
我们定义一个操作get(a, l, r)表示查询a序列[l,r]区间内的最大子段和,那么最终要求的答案就是get(nums, 0, nums.size()-1)。如何分治实现这个操作呢?对于一个区间[l,r],我们取,对区间[l,m]和[m+1,r]分治求解。当递归逐层深入直到长度缩小为1的时候,递归【开始回升】。这个时候我们考虑如何通过[l,m]区间的信息和[m+1,r]区间的信息合并成区间[l,r]的信息。最关键的两个问题是:
- 我们要维护区间的哪些信息呢?
- 我们如何合并这些信息呢?
对于一个区间 [l,r],我们可以维护四个量:
- lSum 表示 [l,r] 内以 l 为左端点的最大子段和
- rSum 表示 [l,r] 内以 r 为右端点的最大子段和
- mSum 表示 [l,r] 内的最大子段和
- iSum 表示 [l,r] 的区间和
以下简称[l,m]为[l,r]的左子区间,[m+1,r]为[l,r]的右子区间 。我们考虑如何维护这些信息呢(如何通过左右子区间的信息合并得到[l,r]的信息)。对于长度为1的区间[i,i],四个量的值都和nums[i]相等。对于长度大于 1 的区间:
1、首先最好维护的是 iSum,区间 [l,r] 的 iSum 就等于【左子区间】的 iSum 加上【右子区间】的 iSum。
2、对于[l,r]的lSum,存在两种可能,它要么等于【左子区间】的lSum,要么等于【左子区间】的lSum加上【右子区间的】lSum,二者取最大。
3、对于[l,r]的rSum,同理,它要么等于【右子区间】的rSum,要么等于【右子区间】的rSum加上【左子区间】的rSum加上右子区间的rSum。
4、当计算好上面的三个量之后,就很好计算[l,r]的mSum了。我们可以考虑[l,r]的mSum对应的区间是否跨越m——它可能不跨越m,也就是说[l,r]的mSum可能是【左子区间】的mSum和【右子区间】的mSum中的一个;它也可能跨越m,可能是【左子区间】的rSum和【右子区间】的lSum求和。三者取最大。这样问题就得到了解决。如下为实现代码:
class Solution {
public:struct Status {int lSum, rSum, mSum, iSum;};Status pushUp(Status l, Status r) {int iSum = l.iSum + r.iSum;int lSum = max(l.lSum, l.iSum + r.lSum);int rSum = max(r.rSum, r.iSum + l.rSum);int mSum = max(max(l.mSum, r.mSum), l.rSum + r.lSum);return (Status) {lSum, rSum, mSum, iSum};};Status get(vector<int> &a, int l, int r) {if (l == r) {return (Status) {a[l], a[l], a[l], a[l]};}int m = (l + r) >> 1;Status lSub = get(a, l, m);Status rSub = get(a, m + 1, r);return pushUp(lSub, rSub);}int maxSubArray(vector<int>& nums) {return get(nums, 0, nums.size() - 1).mSum;}
};
时间复杂度:假设我们把递归的过程看作是一颗二叉树的先序遍历,那么这颗二叉树的深度的渐进上界为 O(logn),这里的总时间相当于遍历这颗二叉树的所有节点,故总时间的渐进上界是 ,故渐进时间复杂度为 O(n)。空间复杂度:递归会使用 O(logn) 的栈空间,故渐进空间复杂度为 O(logn)。
分治方法相比动态规划(方法二)的优势:它不仅可以解决区间 [0,n−1],还可以用于解决任意的子区间 [l,r] 的问题。如果我们把 [0,n−1] 分治下去出现的所有子区间的信息都用堆式存储的方式记忆化下来,即建成一棵真正的树之后,我们就可以在 O(logn) 的时间内求到任意区间内的答案,我们甚至可以修改序列中的值,做一些简单的维护,之后仍然可以在 O(logn) 的时间内求到任意区间内的答案,对于大规模查询的情况下,这种方法的优势便体现了出来。这棵树就是上文提及的一种神奇的数据结构——线段树。
笔者小记:
1、动态规划与分治法和贪心法类似,都是将问题分解为更小的子问题,并通过求解子问题来得到全局最优解。然而,它们在处理子问题的方式上有所不同:
- 贪心法:当前选择依赖于已经作出的所有选择,但不依赖于有待于做出的选择和子问题。它自顶向下,一步一步地作出贪心选择。
- 分治法:各个子问题是独立的,一旦递归地求出各子问题的解后,自下而上地将子问题的解合并成问题的解。
- 动态规划:允许子问题不独立,通过自身子问题的解作出选择,对每一个子问题只解一次,并将结果保存起来,避免每次碰到时都要重复计算。
解决问题的时候,应根据题目要求划分采用贪心思想、动态规划思想、分治思想三类思想的哪类问题,再进行代码的实现,三种思想时间复杂度都较低,单层循环逻辑可实现。
相关文章:
编程题-最大子数组和(中等-重点【贪心、动态规划、分治思想的应用】)
题目: 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组是数组中的一个连续部分。 解法一(枚举法-时间复杂度超限): …...
阿里云视频点播,基于thinkphp8上传视频
前端参考官方示例(jQuery版) <!DOCTYPE html> <html> <head><meta charset"utf-8"><title>阿里云 JavaScript上传SDK Demo (使用jquery)</title><script src"__STATIC__/jquery.min.js"></script><sc…...
《探秘AI绿色计算:降低人工智能硬件能耗的热点技术》
在人工智能飞速发展的当下,其硬件能耗问题愈发凸显。据国际能源署预测,人工智能的能源消耗可能大幅增长。因此,降低人工智能硬件能耗,实现绿色计算,已成为行业关键课题。以下是一些正在崭露头角的热点技术。 新型硬件…...
神经网络常见激活函数 9-CELU函数
文章目录 CELU函数导函数函数和导函数图像优缺点pytorch中的CELU函数tensorflow 中的CELU函数 CELU 连续可微指数线性单元:CELU(Continuously Differentiable Exponential Linear Unit),是一种连续可导的激活函数,结合了 ELU 和 …...
软考高级《系统架构设计师》知识点(四)
嵌入式技术 第二版新增内容 嵌入式系统:以应用为中心、以计算机技术为基础,并将可配置与可裁减的软、硬件、集成于一体的专用计算机系统,需要满足应用对功能、可靠性、成本、体积和功耗等方面的严格要求。一般嵌入式系统由嵌入式处理器、相关…...
opencv交叉编译
适用于瑞芯微,海思,酷芯等ARM平台。采用编译脚本配置编译选项,方便编译。 目录 一、创建目录 二、工具链配置 三、编译脚本 四、编译 一、创建目录 mikemike-virtual-machine:opencv-4.12/opencv/opencv$ tree . -L 1 . ├── 3rdpart…...
安装vite报错Install for [ ‘create-vite@latest‘ ] failed with code 1
报错内容: npm ERR! code ENOLOCAL npm ERR! Could not install from “Files\nodejs\node_cache_npx\31400” as it does not contain a package.json file. npm ERR! A complete log of this run can be found in: npm ERR! D:\Program Files\nodejs\node_cache_…...
Spring框架中都用到了哪些设计模式?
大家好,我是锋哥。今天分享关于【Spring框架中都用到了哪些设计模式?】面试题。希望对大家有帮助; Spring框架中都用到了哪些设计模式? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring框架中使用了大量的设计模…...
LabVIEW 中 dotnet.llb 库功能
在 LabVIEW 功能体系里,位于 C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform\dotnet.llb 路径下的 dotnet.llb 库意义重大。作为与 .NET 技术交互的关键库,它使 LabVIEW 用户能够与基于 .NET 框架开发的应用程序和组件进行交…...
C# 变量,字段和属性的区别
总目录 前言 在C#中,变量(Variables)、字段(Fields) 和 属性(Properties) 是三个容易混淆但作用截然不同的概念。以下是它们的核心区别与使用场景: 一、变量(Variables&…...
wordpress模板文件结构超详解
wordpress网站建设中,主题的制作是最为核心的环节。了解模板文件结构是模板制作的第一步,本文所讲的模板文件结构包括两部分,一是指以文件名为概念的文件结构,二是指文件内容的代码结构。 一、如何使模板文件起作用 ↑ wordpres…...
android studio下载安装汉化-Flutter安装
1、下载android studio官方地址:(这个网址可能直接打不开,需要VPN) https://developer.android.com/studio?hlzh-cn mac版本分为X86和arm版本,电脑显示芯片是Inter的就是x86的,显示m1和m2的就是arm的 …...
数据开放共享和平台整合优化取得实质性突破的智慧物流开源了
智慧物流视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒,省去繁琐重复的适配流程,实现芯片、算法、应用的全流程组合,从而大大减少企业级应用约95%的开发成本可通过边缘计算技术…...
如何设置 Nginx 连接超时并进行测试(Nginx优化)
🏡作者主页:点击! Nginx-从零开始的服务器之旅专栏:点击! 🐧Linux高级管理防护和群集专栏:点击! ⏰️创作时间:2025年2月15日14点22分 在高并发场景下,如…...
springboot整合mybatis-plus(保姆教学) 及搭建项目
一、Spring整合MyBatis (1)将MyBatis的DataSource交给Spring IoC容器创建并管理,使用第三方数据库连接池(Druid,C3P0等)代替MyBatis内置的数据库连接池 (2)将MyBatis的SqlSessionFactory交给Spring IoC容器创建并管理,使用spring-mybatis整…...
知识管理成功:关键指标和策略,研究信息的投资回报率
信息过载会影响生产力。没有人工智能的帮助,信息过载会影响生产力。大量的可用信息,知识工作者不仅仅是超负荷工作;他们感到不知所措,他们倾向于浪费时间(和脑细胞)来应付他们被大量的数据抛向他们…...
【算法】链表
零:链表常用技巧 1:引入虚拟头结点 (1)便于处理边界情况 (2)方便我们对链表操作 2:两步尾插,头插 (1)尾插 tail指向最后一个节点,tail.next…...
集成测试总结文档
1. 集成测试的定义 集成测试(Integration Testing)是在单元测试之后,将多个独立的软件模块或组件组合在一起进行测试的过程,目的是验证这些模块之间的接口、数据传递、协作逻辑是否符合设计要求,并发现因集成引发的缺…...
关于Dest1ny:我的创作纪念日
Dest1ny 因为这是csdn任务,我就稍微“写”了一下! 如果大家真的有什么想聊的或者想一起学习的,欢迎在评论区或者私信中与我讨论! 2025想说的话 我就把我想说的写在前面! 不用对未来焦虑,不要觉得自己走…...
Python爬虫-猫眼电影的影院数据
前言 本文是该专栏的第46篇,后面会持续分享python爬虫干货知识,记得关注。 本文笔者以猫眼电影为例子,获取猫眼的影院相关数据。 废话不多说,具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。接下来,跟着笔者直接往下看正文详细内容。(附带完整代码) …...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
全球首个30米分辨率湿地数据集(2000—2022)
数据简介 今天我们分享的数据是全球30米分辨率湿地数据集,包含8种湿地亚类,该数据以0.5X0.5的瓦片存储,我们整理了所有属于中国的瓦片名称与其对应省份,方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
【C++进阶篇】智能指针
C内存管理终极指南:智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
Oracle11g安装包
Oracle 11g安装包 适用于windows系统,64位 下载路径 oracle 11g 安装包...
