最大子数组问题——编程珠玑第八章

分治算法求子数组的最大和 求最大子数组和也是一个非常经典的题目。此题目在leetcode,《编程之美》,《算法导论》,《编程珠玑》中都提到了,这是一个能显著体现出算法设计重要性的题目。通过不断地优化算法设计,该题目能够不断以更好更快的时间被解决。先看一下题目描述: 题目描述: 输入一个整形数组,数组里有正数也有负数。 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。 求所有子数组的和的最大值。要求时 阅读详情

问题:给定数组a[n],求其子数组的最大和。例如输入数组为:

1,-2,3,10,-4,7,2,-5

和最大的子数组为3,10,-4,7,2,因此输出为18.

没有想到更“巧妙”的算法前,用所谓“暴力”算法一般都能解决:

1、简单算法:

       求出每个子数组的和,记录最大的那个即可。

void    maxSum_1(int a[], int n)
{
    int sum=NM,m=NM;//NM是一个很小的负数,例如-99999999.下同
    for(int i=0; i<n; i++)
    {
        sum=0;
        for(int j=i; j<n; j++)
        {
            sum += a[j];
            m = max(m,sum);
        }
    }
    cout<<__FUNCTION__<<" : "<<m<<endl;
}

算法复杂度是O(n2).书中的算法还有一个O(n3)的,比上面这个复杂之处是求sum时再从头开始,此处就不再提了。

2、分治法

       把数组分成均等的两段l和u,那么原问题的解就是:最大子数组要么在l中,要么在u中,要么横跨l和u。

横跨中点时的情况比较难理解:这时左面不再是求最大子数组,而是从中间向两边求最大和。

int    maxSum_2_helper(int a[], int l, int u)
{
    if(l>u)     return  NM;		//非法参数
    if(l==u)    return  a[l];		//只有一个元素
    int m = (l+u)/2 ;
    ///求左面一半的连续最大和
    int lmax=NM;
    for(int i=m,s=0; i>=l; i--)///从中点到最左端
    {
        s += a[i];
        lmax = max(lmax,s);
    }
    ///求右面一半的连续最大和
    int rmax=NM;
    for(int i=m+1,s=0; i<=u; i++)
    {
        s += a[i];
        rmax = max(rmax,s);
    }
   ///合并结果
   ///rlm是左右子数组中的最大子数组的和
    int rlm = max(maxSum_2_helper(a,l,m), maxSum_2_helper(a,m+1,u)) ;
    return  max(rlm,lmax+rmax);///合并跨越中点的和两边的最大和
}

void    maxSum_2(int a[], int n)
{
    int m=maxSum_2_helper(a,0,n-1);
    cout<<__FUNCTION__<<" : "<< m <<endl;
}

该算法非常微妙,其复杂度是O(nlogn).


3、巧妙的扫描算法

       考虑如果我们已经求得a[0…i-1]的最大子数组和为m,那么a[0…i]的最大子数组要么在0~i-1中(存储在maxSoFar),要么截止到i(存储在maxEndingHere)。


void    maxSum_3(int a[], int n)
{
    int maxSoFar=NM, maxEndingHere=NM;
    for(int i=0; i<n; i++)
    {
        maxEndingHere = max(maxEndingHere+a[i], a[i]);
        maxSoFar = max(maxSoFar,maxEndingHere);
    }
    cout<<__FUNCTION__<<" : "<< maxSoFar <<endl;
}

这个算法的另一种形式:

void    maxSum_3_2(int a[], int n)
{
    int m=NM, sum=0;
    for(int i=0; i<n; i++)
    {
        sum += a[i];
        m = max(m,sum);
        if(sum<0)
            sum = 0;
    }
    cout<<__FUNCTION__<<" : "<< m <<endl;
}

相关问题:

a)查找总和最接近0的连续子数组,更一般的情况,查找最接近给定实数t的连续子数组。

       如果a[i…j]最接近0,那么a[0…i]的和就与a[0…j]的和最接近。所以使用累加数组即可。由原数组构造新数组s[n](或者直接在原数组上操作),使s[i]=sum(a[0…i])。然后对s[n]排序,求出s[n]中最接近的两个数。这两个数的差值即为最接近0的子数组和。需要说明的是,这时需要新建数据结构,记录原来数组中每个元素的位置。

由于排序最快为O(nlogn),因此这个时间复杂度O(nlogn),空间O(n).

代码如下,使用stl的排序函数sort。

struct   AP
{
    int value;
    int pos;
};
bool    operator<(const AP & n, const AP &m)
{
    return  n.value<m.value;
}

template  <typename T>
inline  T   abs(T n)
{
    return  n<0?(-n):n;
}

int    nearZero(int a[], int n)
{
    AP *b=new AP[n]();
    int sum=0;
    for(int i=0;i<n;i++)
    {
        b[i].pos = i;
        sum += a[i];
        b[i].value = sum;
    }
    sort(b,b+n);
    ///寻找差绝对值最小的两个元素
    int dmin=NM;
    int t = 0;
    for(int i=1; i<n; i++)
    {
        if( abs(dmin) > abs(b[i].value - b[i-1].value))
        {
            dmin = abs(b[i].value - b[i-1].value);
            t = i;
        }
    }
    ///t 和 t-1 位置元素之差极为最接近0
    int r=NM;
    int s,e;///s为子数组起始下表,e为子数组末尾下表
    if(b[t].pos<b[t-1].pos)
    {
        r = b[t-1].value - b[t].value;
        s = b[t].pos + 1;
        e = b[t-1].pos;
    }
    else
    {
        r = b[t].value - b[t-1].value;
        s = b[t-1].pos + 1;
        e = b[t].pos;
    }
    cout<<__FUNCTION__<<" : "<< r <<endl;
    cout<<"["<<s<<","<<e<<"]"<<endl;

    delete [] b;
    return r;
}


     对于任意实数的问题,目前还没想到合适的解法。开始觉得对数组中每个元素平移是一个貌似可行的解决方法,但是仔细分析后发现是不行的。

  后序还有最大子矩阵问题。

未完待续。

参考:http://www.cnblogs.com/wuyuegb2312/p/3139925.html


【吐血整理-历时两个月,长达万字】FDTD Solutions学习笔记 原教学视频来自于Ansys-Lumerical官方的FDTD100,所看视频来自B站大佬UP主 【Nestor_呐等】 的幸苦翻译,本文内容粘贴自我个人在学习FDTD100时,通过字幕和一些个人理解总结的一份word。整理不易,强烈建议收藏!... 阅读详情

相关推荐

SPM12最新安装教程:Matlab2021a用户必看的路径配置技巧

本文为Matlab2021a用户提供SPM12的深度安装与路径配置指南。针对新版Matlab的路径管理变化,详细解析了传统方法失效的原因,并推荐通过创建startup.m文件实现SPM12路径的永久化、自动化配置,确保神经影像分析环境的稳定与高效。

weixin_29061509的博客 315

《编程珠玑》代码之路11:最大子数组和问题,花式七种解法

给一个一维数组,有正数也有负数,求最大子数组和是多少。 这是《编程珠玑》第八章探讨的一个主要问题,也是平时刷题和各大厂面试的常客。 作为这么经典的一个问题,要是老生常谈,那就没什么意义了,这里为大家带来七种解法,其中更有一个最优复杂度的线性算法,博主在各大厂面试的时候,碰到的面试官也非常惊讶有这么一个解法的存在。自然问到这个问题的面试,都理所当然的过了。(本博客代码不会考虑溢出等工程问题)。 ...

beijixiong5622的专栏 596

南大计算机2024保研笔试:编译原理等5门专业课考点分布与408复习避坑指南

本文详细解析了南京大学计算机2024保研笔试的考点分布与复习策略,重点突出编译原理(占比28%-32%)和离散数学的特色考核。提供跨课程复习方法、真题题型分析及高效备考建议,帮助考生突破传统408框架,应对南大独特的命题风格。

weixin_29304985的博客 345

最大子数组问题的两种解法

所谓最大子数组就是连续的若干数组元素,如果其和是最大的,那么这个子数组就称为该数组的最大子数组。最大子数组是很多问题的抽象,比如购买股票。如果把相邻两天的股价之差作为数组元素,那么求在连续的某个时间段内买入股票的最佳时间和卖出股票的最佳时间就可以抽象为计算最大子数组的问题。下面分别介绍两种算法求解最大子数组问题,算法思想均来自算法导论这本程序员的圣经。 分治法 分治法实现思路比较简单。如果把一...

T-tian的博客 8079

ISA-95(S95)标准详解

ISA-95是制造业系统集成的“通用语言”,通过分层模型和信息流规范,打通企业计划层与设备控制层,成为实现数字化工厂的核心标准之一。其与ISA-88的协同应用,可进一步优化生产执行与资源管理的效率。标准,旨在解决企业商业系统(如ERP)与工业控制系统(如MES、SCADA)之间的集成问题。

「东哥说MES」 专注于MES制造执行系统,为你拆解核心架构、功能模块及与ERP/PLC的集成逻辑。提供从入门到精通的系列干货、精选行业报告与实用工具,构建你的数字化知识体系,关注我,用实战经验照亮你的数字化之路。 3737

LTSPICE仿真电路:(二十八)三极管厄利电压与输出特性曲线深度解析

本文深入解析了LTSPICE仿真电路中三极管的厄利电压与输出特性曲线,详细介绍了厄利电压的物理意义、仿真设置及实际应用。通过伏安特性曲线和厄利电压的分析,帮助读者理解三极管放大性能的关键参数,并提供了电路设计中的优化方案和故障排查技巧。

weixin_26899659的博客 149

最大子数组问题

1. 问题描述 对于数组(如下),求解其最大子数组. 结果为: 2. 算法设计 采用递归的方法求解 A. 求解数组左半部分的最大子数组 B. 求解数组右半部分的最大子数组 C. 求解整个数组的最大子数组 D. 比较A,B,C求出的结果,选出一个最大值,即为最终结果. 3. 数据结构设计 A. 中间结果的三元组,(子数组下标,子数组上标...

Jeff1215的博客 200

从零到一:手把手教你用C#开发AGV调度系统(附避坑指南)

本文详细介绍了如何使用C#开发高效的AGV调度系统,涵盖从环境搭建到核心算法实现的完整流程。重点解析了动态路径规划、多机协同等关键技术,并提供了实用的避坑指南和性能优化建议,帮助开发者快速构建工业级车辆控制调度系统。

blockchain9miner的博客 742

最大子数组之和 2

题目:返回一个整数数组中最大子数组的和 要求:(在原有代码上进行迭代) 1.输入一个整数数组,数组中有正数和负数。 2.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。 3.如果数组a[0]……a[n-1]首尾相邻,允许a[i-1]……a[n-1]、a[0]……a[j-1]之和最大。 4.同时返回最大子数组的位置。 5.求所有子数组的和的最大值。 分析: ...

weixin_30502965的博客 164

避坑指南:Qwen2.5-VL图片预处理中常见的5个尺寸错误

本文深入解析了Qwen2.5-VL模型在图片预处理环节中开发者最常遇到的五个尺寸错误,包括动态分辨率对齐、宽高比超标、像素数限制等问题。文章结合源码解读,详细剖析了`process_vision_info`函数和`resize`逻辑,并提供了具体的排查流程图与参数设置建议,旨在帮助开发者构建健壮的预处理流水线,有效规避显存溢出与推理失败的风险。

weixin_29290379的博客 178

ANSA二次开发在线帮助:ANSA和μETA API文档

  为了方便大家学习ANSA二次开发,我将ANSA和μETA二次开发的官方文档整合到了我的个人网站CAECoder中,大家点击ANSA和μETA API官方帮助文档进行访问即可查看。   本站也将开展对ANSA和μETA API文档的翻译工作,请大家持续关注! ANSA和μETA API文档   ANSA和μETA脚本接口是一个应用程序编程接口(API),允许开发人员访问ANSA和μETA核心功能和数据。   ANSA和μETAAPI是Python编程语言的扩展。 Python Python简.

CAECoder 4322

扫描算法 编程珠玑

编程珠玑第八章,maxsofar保存的是第i个元素之前的最大子数组和 maxsofar=0 maxendinghere=0 for i=[0,n) maxendinghere=max(maxendinghere+x[i],0) maxsofar=max(maxsofar,maxendinghere) for(int i=0; i<len; ++i ) {

john_and_betty的专栏 602

Esp32蓝牙Hid调用方案 http执行设备、鼠标、键盘相关操作

本文主要介绍 Esp32 蓝牙 Hid 相关的多种操作方式,详细的设备、鼠标、键盘相关操作的 http 调用方法。下面是整理出的所有 http 调用方法和 rhino 引擎方式。本机调用的话直接使用http://localhost:8080 如果是局域网调用则使用软件里的地址 比如我的是http://192.168.1.5:8080。文件地址: https://www.123865.com/s/Qtm4jv-xyZbd?使用前需要一块烧录好的ESP32板子并在手机安装好embedded软件用于蓝牙通信。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 569

编程珠玑读后感1(1个算法)

在《编程珠玑》第八章,作者提出一道算法题:程序描述:输入是一个具有N个浮点数字的向量X: 其输出是在输入的任何相邻子向量中找出的最大和。例如,输入如下10个元素:31 -41 59 26 -53 58 97 -93 -23 84返回 x[2..6]的总和,或为187作者分别给出了三次算法O(n^3),两个二次算法O(n^2),分治算法O(n logn )和扫描算法O(n)。

hongjiqin的专栏 1805

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

[编程珠玑]-第八章:连续子向量的最大和

源于编程珠玑-第二版 问题描述: 一维模式识别,输入n个数值向量x,输出连续子向量的最大和。 题目很简单,即求最大子数组。 1.平方算法:O(n^2) 需要对所有连续组合进行对比,选择出累积和最大的值,算法的优化在于减少反复计算对比。 对于X[i...j]的总和,与前X[i...j-1]的总和密切相关,  省去反复计算i~j的值 max=0 for i=[0,n) sum=0

only06的博客 520

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

线性时间解决最大子数组问题

最大子数组问题又叫 maximum-subarray problem,算法导论第三版4.1节有关于其O(nlgn)运行时间的分治法描述,在4.1-5习题中要求给出线性时间的求解方法,这里我给出python的代码: def main(): A = [5,-1,3,-9,10,1] max = max_subarray(A) print max def max_subarr

计算机随笔 1400

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

编程之美--求子数组之和的最大值

<br />编程之美和编程珠玑上面都有这个经典的例子,珠玑甚至用了第八章整整一章来阐述这个例子,这里对算法的细节就不加以阐述了,(我可以肯定没有这两本书中解释的清楚……),但是我对编程之美的扩展问题进行了求解(珠玑的题目比较深奥,还没有深入解答)。<br /> <br />在这里先说扩展问题的第二题:<br />这里以最后一种算法为基础进行扩展,每次当A[i] > nStart + A[i]时,也就是nStart大于零的时候更新数组的起始index,并且最后输出的起始index应该为该值减一(可以想一想为什

hitrose27的专栏 1038

编程珠玑第八章——习题10查找数组中总和最接近0的子数组

方法1: 这个问题和求子数组最大值优点相似,但解法不同,如果按照求子数组最大值的方法来求解,我们可以求出以j为截止的最大值和最小值,如果最大值和最小值都>0,那么最小值即为所求,如果都0而最小值

坚持 721

《编程珠玑》第八章算法的简单C语言实现

#define max(a, b) ((a)<(b)?(b):(a)) int arr[] = {31, -41, 59, 26, -53, 58, 97, -93, -23, 84}; //扫描算法 int scanning_algorithm() { int maxsofar = 0; int maxendinghere = 0; for (int i = 0; i &lt...

qu1993的博客 271

编程珠玑读后感

该书喜欢引用论文,理论性很强。由于出版时间的问题,本书介绍的算法在现在看来可能已经非常普遍了。中文版翻译的也有些生硬。

将~军的博客 1116

编程珠玑第八章 算法设计艺术

问题描述: 一个具有n个浮点数字的数组x,目标是要找到之中连在一起的数组元素中找到最大和。例如如果输入的数组是以下这十个元素: 31 -41 59 26 -53 58 97 -93 -23 84 那么程序应该返回从59到97的综合,也就是187。第一个算法迭代了所有满足 0 ≤ i ≤ j < n 的 i 和 j 整数对,分别计算总和,最终找到综合最大的组合。 问题定义:...

weixin_30595035的博客 230

《编程珠玑》笔记

第二章例子:将一个具有n个元素的一围向量向左旋转i个位置。例如假设n=8,i=3,那么向量abcdefgh旋转后为defghabc解法:先考虑ab,转置a得到a`b,再转置b得到a`b`,然后再转置整个a`b`得到(a`b`)`,实际上就是ba。这就导致了下面产生 旋转作用的代码,注释显示了abcdefgh向左旋转三个元素的结果。reverse(0,i-1)  //cbadefgh

门外汉的专栏 1586

编程珠玑第八章-算法设计技术

本章就一个小问题研究了四种不同的算法,重点强调了这些算法的设计技术,综合本章内容,告诉我们:复杂深奥的算法有时可以极大地提高程序性能。 问题定义: 具有n个浮点数的向量x,求出输入向量的任何连续子向量的最大和。 立方算法: maxsofar = 0; for i = [0,n)     for j=[i,n)         sum = 0;         for k=

日新为道的专栏 1039

编程珠玑——第八章习题10扩展和习题11

习题10求解的是查找数组中总和最接近于0的子数组

坚持 706
上一篇: 实习面试总结
下一篇: 矩形子数组的最大和
quickSort
博客等级 码龄15年 51粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值