3.4 最大字段和

news2025/1/4 19:25:47


  • 博主简介:一个爱打游戏的计算机专业学生
  • 博主主页: @夏驰和徐策
  • 所属专栏:算法设计与分析

1.什么是最大子段和?

我的理解:

最大子段和是一个经典的问题,也称为最大子数组和问题。给定一个整数数组,要求找到数组中连续子数组的和的最大值。这个连续子数组可以为空,但其和必须是数组中所有连续子数组中最大的。

形式化地说,对于给定的整数数组 A,最大子段和问题可以表示为:找到数组 A 中的两个索引 i 和 j(其中 0 ≤ i ≤ j < n),使得子数组 A[i:j] 的元素之和最大。

例如,对于数组 A = [-2, 1, -3, 4, -1, 2, 1, -5, 4],最大子段和为子数组 [4, -1, 2, 1],其和为 6。

解决最大子段和问题的常用算法是动态规划算法,具体的思路是通过迭代更新子数组的和,同时记录最大值。该算法的时间复杂度为 O(n),其中 n 是数组的长度。

 2.最大子段和问题的简单算法

源代码:

int MaxSum(int n,int *a,int& besti,int& bestj)
{
	int sum=0;
	for(int i=1;i<=n;i++)
	{
		for(int j=i;j<n;j++)
		{
			int thissum=0;
			for(int k=i;k<=j;k++)
			{
				thissum+=a[k];
				if(thissum>sum)
				{
					besti=i;
					bestj=j;
				}
			}
		 } 
	}
	return sum;
}

代码思路:

我的理解:

这段代码是一个函数定义,它计算一个数组中连续子数组的最大和,并通过传引用的方式返回最大和对应的子数组的起始和结束索引。

代码的主要部分是三个嵌套的循环。外层的第一个循环迭代变量i用于确定子数组的起始索引,它从1开始遍历到n。内层的第二个循环迭代变量j用于确定子数组的结束索引,它从i开始遍历到n-1。这样的设计是为了考虑所有可能的子数组。

在最内层的第三个循环中,变量k从i遍历到j,用于计算当前子数组的和,即thissum。在每次计算完thissum后,会检查是否该子数组的和大于之前记录的最大和sum。如果是,则更新最大和sum,并记录当前子数组的起始索引besti和结束索引bestj。

最后,函数返回的是sum,即最大和。

然而,这段代码存在一个问题:没有在找到更大的子数组和时更新sum的值。解决方法是在 if (thissum > sum) 的条件判断中添加 sum = thissum; 的语句。这样才能确保函数返回的是正确的最大和。

 逐行解释:

好的,以下是对每一行代码的逐行解释:

第 5 行:定义了一个整数变量 `sum`,用于存储最大和的值。初始值设为 0。

第 7 行:外层循环的起始,迭代变量 `i` 从 1 开始,遍历到 `n`。

第 9 行:内层循环的起始,迭代变量 `j` 从 `i` 开始,遍历到 `n-1`。

第 11 行:定义了一个整数变量 `thissum`,用于存储当前子数组的和。初始值设为 0。

第 13 行:最内层循环的起始,迭代变量 `k` 从 `i` 开始,遍历到 `j`。

第 15 行:将数组中第 `k` 个元素的值加到 `thissum` 上,累计计算子数组的和。

第 17-19 行:如果 `thissum` 大于之前记录的最大和 `sum`,则更新最大和对应的子数组的起始索引 `besti` 和结束索引 `bestj`。

第 23 行:函数返回变量 `sum`,即最大和。

这样,通过逐行解释,你可以更好地理解代码的逻辑和功能。

3.最大子段和问题得分治算法 

int MaxSubSUm(int *a,int left,int right)
{
	int sum=0;
	if(left==right)
	{
		sum=a[left]>0?a[left]:0;
	}
	else
	{
		int center=(left+right)/2;
		int leftsum=MaxSubSum(a,left,center);
		int rightsum=MaxSubSum(a,center+1,right);
		int s1=0;
		int lefts=0;
		for(int i=center;i>=left;i--)
		{
			lefts+=a[i];
			if(lefts>s1)
			{
				s1=lefts;
			}
			int s2=0;
			int rights=0;
			for(int i=center+1;i<=right;i++)
			{
				right+=a[i];
				if(rights>s2)
				{
					s2=rights;	
				} 
				sum=s1+s2;
				if(sum<leftsum)
				{
					sum=leftsum;
				}
				if(sum<rightsum)
				{
					sum=rightsum;
				}
			}
			return sum;
			
		 }
		 int MaxSum(int n,int *)
		 {
		 	return MaxSubSum(a,1,n);	
		 } 
	}
}

 我对这段代码的理解:

代码的功能是计算给定数组的最大子数组和。它使用了分治法的思想,将数组划分为左右两个子数组,分别求解左右子数组的最大子数组和,然后计算包含中间元素的最大子数组和。

具体解释如下:

  • 第 3 行:定义一个整数变量 sum,用于存储最大子数组和的值,初始值为 0。
  • 第 4-7 行:如果 leftright 相等,说明只有一个元素,将 sum 设置为该元素的值(如果大于 0),否则设置为 0。
  • 第 9-15 行:如果有多个元素,则计算数组的中间索引 center
  • 第 16-17 行:递归调用 MaxSubSum 函数,分别求解左右两个子数组的最大子数组和。
  • 第 18-23 行:初始化变量 s1lefts,并从中间元素向左遍历,累计计算左半部分的最大子数组和。
  • 第 24-30 行:初始化变量 s2rights,并从中间元素的右侧开始向右遍

三目运算符:

 

三目运算符(也称为条件运算符)是一种在条件为真或假时选择不同操作的简洁方式。它的语法形式如下:
条件表达式 ? 表达式1 : 表达式2

其中,条件表达式的结果为真(非零值)或假(零值)。如果条件为真,整个表达式的结果为表达式1的值;如果条件为假,整个表达式的结果为表达式2的值。

以下是一个示例,说明如何使用三目运算符:
int a = 10;
int b = 5;
int max = (a > b) ? a : b;

在上述示例中,条件表达式 `(a > b)` 判断变量 `a` 是否大于变量 `b`。如果条件为真,将返回变量 `a` 的值;如果条件为假,将返回变量 `b` 的值。因此,变量 `max` 将被赋值为 `a` 的值(即 10)。

三目运算符可以简化某些条件下的逻辑判断和赋值操作,使代码更加简洁和易读。然而,使用时要注意不要过度使用或使代码难以理解。在某些情况下,使用常规的 `if-else` 语句可能更加清晰和易于维护。

 

4.最大子段和问题与动态规划算法的推广 

最大子段和问题是最大子数组和问题的一个推广。在最大子段和问题中,我们考虑的是连续子段的和,而不仅仅是连续子数组的和。

给定一个整数数组 `a`,最大子段和问题的目标是找到具有最大和的连续子段,并返回该子段的和。

动态规划算法可以推广到解决最大子段和问题。以下是基于动态规划的最大子段和问题的算法思路:

1. 定义状态:我们使用一个一维数组 `dp` 来记录以每个元素结尾的最大子段和。`dp[i]` 表示以第 `i` 个元素结尾的最大子段和。
2. 初始化状态:将 `dp[0]` 初始化为数组的第一个元素 `a[0]`。
3. 状态转移:对于每个元素 `a[i]`,我们有两种选择:
   - 要么将其加入之前的子段中,即 `dp[i] = dp[i-1] + a[i]`;
   - 要么从当前元素开始重新计算子段和,即 `dp[i] = a[i]`。
   我们选择较大的那个作为 `dp[i]` 的值,表示包含第 `i` 个元素的最大子段和。
4. 最终结果:遍历所有的 `dp[i]`,取其中的最大值,即为最大子段和。

这个算法与最大子数组和问题的动态规划算法非常类似,唯一的区别是定义状态的含义。最大子数组和问题关注的是连续子数组的和,而最大子段和问题关注的是连续子段的和。

这个推广后的动态规划算法仍然具有时间复杂度为 O(n),其中 n 是数组的长度。通过动态规划,我们可以有效地解决最大子段和问题,并找到具有最大和的连续子段。

 

5.最大子段和问题与动态规划算法的推广 


int MaxSum(int m, int n, int **a)
{
    int sum = 0;  // 初始化最大子矩阵和为0
    int *b = new int[n+1];  // 创建一个辅助数组b,用于计算子矩阵的元素和
    
    for (int i = 1; i <= m; i++)  // 遍历行
    {
        for (int k = 1; k <= n; k++)  // 将辅助数组b初始化为0
        {
            b[k] = 0;
        }
        
        for (int j = i; j <= m; j++)  // 遍历子矩阵的下边界
        {
            for (int k = 1; k <= n; k++)  // 遍历每列,将元素累加到辅助数组b中
            {
                b[k] += a[j][k];
            }
            
            int max = MaxSum(n, b);  // 调用递归函数MaxSum,计算辅助数组b的最大子数组和
            if (max > sum)  // 如果得到的最大子数组和大于当前最大子矩阵和,则更新最大子矩阵和
            {
                sum = max;
            }
        }
    }
    
    return sum;  // 返回最大子矩阵和
}

 

 

 

总结:

当涉及到最大子段和问题时,可以使用动态规划算法来有效地解决。以下是最大子段和问题的动态规划算法的要点总结:

1. 定义状态:我们可以使用一个一维数组 `dp` 来记录以每个位置结尾的最大子段和。`dp[i]` 表示以第 `i` 个位置结尾的最大子段和。
2. 初始化状态:将 `dp[0]` 初始化为数组的第一个元素 `a[0]`。
3. 状态转移:对于每个位置 `i`,我们有两种选择:
   - 要么将其加入之前的子段中,即 `dp[i] = dp[i-1] + a[i]`;
   - 要么从当前位置重新开始计算子段和,即 `dp[i] = a[i]`。
   我们选择较大的那个作为 `dp[i]` 的值,表示包含第 `i` 个位置的最大子段和。
4. 最终结果:遍历所有的 `dp[i]`,取其中的最大值,即为最大子段和。

根据上述要点,以下是最大子段和问题的动态规划算法的伪代码:

```plaintext
Initialize dp[0] = a[0]

for i from 1 to n-1 do
    dp[i] = max(dp[i-1] + a[i], a[i])

result = max(dp[0], dp[1], ..., dp[n-1])
```

其中,`n` 是数组的长度,`a` 是给定的数组。

通过动态规划算法,我们可以有效地计算出最大子段和,并找到具有最大和的连续子段。该算法的时间复杂度为 O(n),其中 n 是数组的长度。动态规划算法通过利用子问题的最优解来构建整体问题的最优解,解决了最大子段和问题的复杂性。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/602713.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

口撕raft面试100问

1&#xff0c;Raft 协议什么作用 2&#xff0c;详细介绍 Raft 流程 我觉得以下这个流程是比较详细的了&#xff0c; 以下是带上了持久化和日志压缩的细节&#xff1a; 持久化&#xff1a;节点会定期将自己的信息&#xff0c;比如当前任期号、投票信息、日志条目和快照&#…

项目改造操作(图书管理系统为例)

目录 后端 概述 获取所有的读者的借阅卡号 获取所有的未被借阅的图书编号 进行借阅 前端 后端 概述 本模块主要完成对图书的借阅处理。需要实现三个接口&#xff0c;第一个是获取所有的读者的借阅卡号&#xff0c;第二个是获取所有的未被借阅的图书编号&#xff0c;第三…

Spring Boot 启动注解分析

文章目录 1. SpringBootApplication2. EnableAutoConfiguration3. AutoConfigurationImportSelector3.1 isEnabled3.2 getCandidateConfigurations 3.3 removeDuplicates3.4 getExclusions3.5 checkExcludedClasses3.6 removeAll3.7 filter 虽然我们在日常开发中&#xff0c;S…

【Golang】golang中http请求的context传递到异步任务的坑

文章目录 前言一、HTTP请求的Context传递到异步任务的坑 前言 在golang中&#xff0c;context.Context可以用来用来设置截止日期、同步信号&#xff0c;传递请求相关值的结构体。 与 goroutine 有比较密切的关系。 在web程序中&#xff0c;每个Request都需要开启一个goroutin…

使用docker部署nginx并支持https

配置nginx支持https&#xff0c;其实也简单&#xff0c;搞个证书&#xff0c;然后修改下配置文件就好了。我以前一篇文章&#xff08;使用docker部署多个nginx站点并配置负载均衡&#xff09;为例&#xff0c;做个记录。 如前所述&#xff0c;我使用docker&#xff0c;部署了3…

一文带你看懂软件测试(功能、接口、性能、自动化)详解

全文2000字&#xff0c;预计阅读时间10分钟&#xff0c;建议先点赞收藏慢慢看 一、软件测试功能测试 测试用例编写是软件测试的基本技能&#xff1b;也有很多人认为测试用例是软件测试的核心&#xff1b;软件测试中最重要的是设计和生成有效的测试用例&#xff1b;测试用例是测…

面了个京东拿30k出来的,牛逼到家了。。。

今天上班开早会就是新人见面仪式&#xff0c;听说来了个很厉害的大佬&#xff0c;年纪还不大&#xff0c;是上家公司离职过来的&#xff0c;薪资已经达到中高等水平&#xff0c;很多人都好奇不已&#xff0c;能拿到这个薪资应该人不简单&#xff0c;果然&#xff0c;自我介绍的…

RK平台如何配置USB功能

简介 RK平台基本能够通过dts配置就能实现USB功能。为了方便理解&#xff0c;我这里分三部分来介绍&#xff0c;包括&#xff1a;usb-phy&#xff0c;usb控制器&#xff0c;usb供电。 usb-phy usb-phy负责最底层的信号转换&#xff0c;主要是硬件的差分信号转换成数字信号传给…

十条ChatGPT常用的Prompt

Prompt 本文数据来源&#xff1a;Will 3.6-6.16 硅谷&#xff0c;原作者&#xff1a;rowancheung 一&#xff0c;简化复杂的信息 Prompt&#xff1a; 将&#xff08;主题&#xff09;分解成更小、更容易理解的部分。使用类比和现实生活中的例子来简化概念并使其更相关 Brea…

Python之并发多线程操作

一、threading模块介绍 multiprocess模块的完全模仿了threading模块的接口&#xff0c;二者在使用层面&#xff0c;有很大的相似性 二、开启线程的两种方式 方式一 #方式一 from threading import Thread import time def sayhi(name):time.sleep(2)print(%s say hello %na…

最大公约数(GCD) 与 最小公倍数(LCM)的 定义、关系、求法

最大公约数 与 最小公倍数 约数 和 倍数最大公约数最小公倍数 最大公约数与最小公倍数的关系求最大公约数、最小公倍数例一例二 约数 和 倍数 如果数 a a a能被数 b b b整除&#xff0c; a a a就叫做 b b b的倍数&#xff0c; b b b就叫做 a a a的约数。 约数和倍数都表示一个…

从0-1实战react项目

文章目录 1. 安装2. 完成一个组件开发3. 添加路由3. 引入element-react1. 运行发现报错./node_modules/element-react/dist/npm/es5/src/locale/format.js2. 接着又报错The <Router /> component appears to be a function component that returns a class instance. Cha…

[SpringBoot]关于Profile配置文件关于Slf4j日志

关于Profile配置文件 在Spring系列框架中&#xff0c;关于配置文件&#xff0c;允许同时存在多个配置文件&#xff08;例如同时存在a.yml、b.yml等&#xff09;&#xff0c;并且&#xff0c;你可以按需切换某个配置文件&#xff0c;这些默认不生效、需要被激活才生效的配置&am…

【ProtoBuf】protobuf序列化协议

Protobuf介绍 Protobuf (Protocol Buffers) 是谷歌开发的一款无关平台&#xff0c;无关语言&#xff0c;可扩展&#xff0c;轻量级高效的序列化结构的数据格式&#xff0c;用于将自定义数据结构序列化成字节流&#xff0c;和将字节流反序列化为数据结构。所以很适合做数据存储…

容器底层实现技术

一、Namespace 和 Cgroup 1、容器技术发展历史 2、Docker 容器实现原理 1. Docker 容器在实现上通过 namespace 技术实现进程隔离&#xff0c; 通过Cgroup 技术实现容器进程可用资源的限制 3、Namespace Namespace &#xff1a;命名空间 1. 作用&#xff1a;资源隔离 2. 原理&…

web前端课程作业设计:个人简历

一.说明 今天博主的web前端选修课结课了&#xff0c;期末大作业也提交了&#xff0c;今天写一篇博客把我的大作业分享给大家。 二.题目 1. 大作业题目 个人简历主页设计 2. 内容要求 应尽量包含以下内容&#xff1a; 包含个人基本信息、教育背景、个人风采、与我联系四块…

企业四要素核验-企业四要素核验接口-api接口

接口地址&#xff1a; https://登录后显示/pyi/184/358(支持:http/https)) 在线查询&#xff1a;https://www.wapi.cn/api_detail/184/358.html 网站地址&#xff1a;https://www.wapi.cn 返回格式&#xff1a;json,xml 请求方式&#xff1a;GET,POST 请求说明&#xff1a; …

【实用篇】Elasticsearch01

分布式搜索引擎01 – elasticsearch基础 1.初识elasticsearch 1.1.了解ES 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 例如&#xff1a; 在GitHub搜索…

智慧公厕系统如何通过物联网技术提高公厕的管理效率

智慧公厕系统可以通过物联网技术&#xff0c;实现公共卫生间的智能化管理和服务&#xff0c;提高管理效率。本文将详细介绍智慧公厕系统如何通过物联网技术提高公共卫生间的管理效率&#xff0c;从硬件、软件、系统等方面逐一分析。 XP-智慧厕所方案-HYF20230328&#xff08;16…

工业企业为什么要用边缘计算网关?

在我们进入智能制造和工业4.0的新时代&#xff0c;工业企业的数据需求正急速增长。传感器&#xff0c;机器和设备每分钟都在产生大量数据&#xff0c;它们对实时处理和分析的需求比以往任何时候都要强烈。这就是为什么工业企业需要边缘计算网关。 边缘计算网关在物联网架构中担…