高频算法:Leetcode53 最大子数组和

news2024/10/6 5:18:02

今天讲的是Leetcode第53题,最大子数组和
最大子数组和
首先观察题目,题目需要我们找出具有最大和的连续子数组,直接拿题目中的示例来做一个演示,找一找什么规律下的连续子数组才能得到最大的和

先从-2开始,-2 + 1 = -1 此时我们的和是一个负数,那么无论后面的数是什么,这个数加上-1一定是更小了,所以-2这个值我们不应该加入到我们的结果子数组中
接下来是1 - 3 = -2,还是一个负数,跟上面一样,我们不需要负数,接下来的-3我们也不要了
此时从4开始找连续的子数组,4 - 1 = 3,是个正数,还能接受,就接着往后加
3 + 2 + 1 = 6,到这里为止,我们得到了迄今为止最大的子数组和
6 - 5 = 1,还是一个正数,还可以接着往后加,1 + 4 = 5,到这里为止整个数组都遍历完了
我们发现最大的子数组和是6,连续子数组为[4, -1, 2, 1]

通过我们对于示例的拆解,我们可以发现一个规律,那就是如果我们在遍历数组的时候,一旦加和为负数的话,这个和就对我们最终的解存在负面效果,所以当前遍历的数组元素就不会在我们的最大连续子数组中
同时我们在得到更大的和时,需要记录下来这个最大的值,因为后面的加和过程中,虽然整体是正数,但也不一定就是最大的,通过这两个条件我们就可以得到我们想要的最大和了

此时我们就可以得到本道题的第一个解法

public int maxSubArray(int[] nums) {
    int result = Integer.MIN_VALUE, sum = 0;
    for (int i = 0; i < nums.length; i++) {
    	// 遍历数组并进行元素的累加
        sum += nums[i];
        // 如果返回的解小于当前我们当前子数组累加的和的话,就重新对解赋值,保证这个解一直是最大的
        if (result < sum) {
            result = sum;
        }
        // 如果子数组的和是负数的话,就舍弃掉当前已经遍历过的子数组,清零后接着往后遍历
        if (sum < 0) {
            sum = 0;
        }
    }
    return result;
}

通过上面发现的规律,我们还可以使用动态规划来解决这道题,首先需要明确的是状态转移方程是怎样的,先将当前的问题进行一下拆解,如果我们要得到最大子数组和,我们需要知道哪些子问题(依旧使用示例来描述)

  1. 如果我们的最大子数组包含-2,最大子数组是什么样的
  2. 如果我们的最大子数组包含1,最大子数组是什么样的
  3. 如果我们的最大子数组包含-3,最大子数组是什么样的
    依次类推,直到数组中的最后一个元素…
  4. 如果我们的最大子数组包含4,最大子数组是什么样的

但是这样定义的话,又不能明确当前这个元素是在数组的哪个位置,不满足动态规划的「无后效性」,简单来说就是有不确定性,这个时候,就需要将子问题定义的更加严格,直接指定子问题中的元素是子数组的最后一个元素,那么我们的子问题就变成了:

  1. 如果我们的最大子数组的最后一个元素是-2,最大子数组是什么样的
  2. 如果我们的最大子数组的最后一个元素是1,最大子数组是什么样的
  3. 如果我们的最大子数组的最后一个元素是-3,最大子数组是什么样的
  4. 如果我们的最大子数组的最后一个元素是4,最大子数组是什么样的

子问题定义完了,那么我们的状态转移方程应该是什么样的呢?我们从第一个子问题出发梳理一下:
如果最后一个元素是-2,那么这个最大子数组其实就是[-2],因为也只有一个元素
如果最后一个元素是1,最大子数组和是 -2 + 1 = -1,这个情况下我们的状态转移方程是dp[i] = dp[i - 1] + nums[i];如果我们将1这个元素换成一个负数,比如说 -1,那么这个子数组和是 -2 - 1 = -3,所以最大子数组和就是 -1,-2就被舍弃掉了
最终我们得到的状态转移方程是dp[i] = Math.max(dp[i - 1] + nums[i], nums[i ])

通过上面的分析,我们可以写出使用动态规划来解决问题的代码

public int maxSubArray(int[] nums) {
	// 将第一个元素先赋值,这样即使数组只有一个元素也不会出问题
    int result = nums[0];
    int[] dp = new int[nums.length];
    // dp[0]的解是确定的
    dp[0] = nums[0];
    for (int i = 1; i < nums.length; i++) {
    	// 状态转移方程
        dp[i] = Math.max(dp[i - 1] + nums[i], nums[i]);
        // 将子问题中最大的和存起来作为结果返回
        result = Math.max(result, dp[i]);
    }
    return result;
}

本人能力有限,可能理解表达不太到位,建议还是看Leetcode上大佬的题解来理解动态规划的思路官网题解

最后一种是题目中提到的分治法,分治法的核心思路也是将一个父问题拆成多个子问题来解决,还是拿题目的示例画一张图来理解一下
分治法思路
[-2,1,-3,4,-1,2,1,-5,4]作为一个完整的数组被分为3部分分别计算最大子数组和:

  1. L部分计算[left, mid]
  2. R部分计算[mid + 1, right]
  3. M部分计算包含mid和mid + 1这两个元素的部分,左边最长延伸到left,右边最长延伸到right

同时对于L和R这两个部分,又可以递归的往下计算分别的最大子数组和,比如L部分,[-2,1,-3,4,-1]这个数组可以继续往下进行分治,直到计算出结果为止

public int maxSubArray(int[] nums) {
    return maxSubArrayDivide(nums, 0, nums.length - 1);
}

private int maxSubArrayDivide(int[] nums, int left, int right) {
    if (left == right) {
        return nums[left];
    }
    int mid = (right - left) / 2 + left;
    // 三个部分取最大的子数组和进行返回
    return Math.max(maxMid(nums, left, mid, right), 
        Math.max(maxSubArrayDivide(nums, left, mid), maxSubArrayDivide(nums, mid + 1, right)));
}

private int maxMid(int[] nums, int left, int mid, int right) {
    int sum = 0, leftSum = Integer.MIN_VALUE, rightSum = Integer.MIN_VALUE;
    // 遍历[left, mid]这个范围内最大的子数组和
    for (int i = mid; i >= left; i--) {
        sum += nums[i];
        if (leftSum < sum) {
            leftSum = sum;
        }
    }
    
    sum = 0;
    // 遍历[mid + 1, right]这个范围内最大的子数组和
    for (int i = mid + 1; i <= right; i++) {
        sum += nums[i];
        if (rightSum < sum) {
            rightSum = sum;
        }
    }
    return leftSum + rightSum;
}

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

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

相关文章

【Python】Python读写.xlsx文件(基本操作、空值补全等)

【Python】Python读写.xlsx文件&#xff08;Pandas&#xff09; 文章目录【Python】Python读写.xlsx文件&#xff08;Pandas&#xff09;1. 介绍2. Pandas读写xlsx文件2.1 基本操作2.1.1 实现任务2.1.2 代码2.1.3 结果2.2 进阶操作2.2.1 写操作2.2.2 查看数据表的基本信息2.2.2…

集中一个主题,密集学习几个月,突飞猛进

集中一个主题&#xff0c;密集学习几个月大长进 诺贝尔奖获得者西蒙发现 密集学习了几个月品牌营销的知识 长进明显 原来是有科学规律的 趣讲大白话&#xff1a;大力出奇迹 【趣讲信息科技132期】 **************************** 西蒙学习法&#xff1a;“对于一个有一定基础的人…

KANO模型-产品需求调研利器

最近要做一个项目&#xff0c;需要调研客户的真实需求&#xff0c;我们有一些可提供的功能&#xff0c;需要通过问卷调研出客户对功能的优先级需求。但问卷调研的结果能反映客户的真实需求和痛点吗&#xff1f;如何给这些需求排优先级&#xff0c;以及所占的权重&#xff1f;如…

【python】只需一段代码,剪辑一个视频——Moviepy详解

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、准备二、视频剪辑三、视频拼接四、逐帧变化四、导出GIF总结前言 知道吗&#xff0c;用moviepy一行代码就能够快速剪辑视频中某个区间的片段&#xff1a; cl…

mac m1系统安装安卓手机模拟器

背景&#xff1a;本人是一名开发人员&#xff0c;本地小程序上的需要地图导航到手机上&#xff0c;所以找到一个mac&#xff08;m1&#xff09;安装安卓模拟器的方案&#xff0c;这里记录分享一下。 废话不多说直接上步骤&#xff0c;很详细跟着步骤走就能完成&#xff01;&am…

【MySQL】delete和truncate的用法和区别

一、delete和truncate的用法 有如下数据表t_student 关键字delete和truncate都用来清除表中数据&#xff0c;语法结构为&#xff1a; delete from t_student;truncate table t_student; 两条SQL操作后的结果一样&#xff1a;删除了表中数据&#xff0c;但是会保留表的结构&a…

OpenAI Embedding:快速实现聊天机器人(一)

theme: orange 本文正在参加「金石计划」 上文 OpenAI Embedding&#xff1a;基于人工智能的搜索新篇章 有讲到Embedding的基础概念以及OpenAI Embedding 的能力和应用场景&#xff0c;这篇文章讲讲如何手把手构建聊天机器人。 聊天机器人介绍 聊天机器人作为一项重要的企业级服…

Qt 数据库SQL

Qt 数据库SQL用户接口层SQL接口层驱动层创建连接数据库查询两个数据库示例用户接口层、SQL接口层和驱动层是数据库系统中的三个重要组成部分&#xff0c;它们分别负责不同的功能。 用户接口层 用户接口层 用户接口层是用户与数据库系统交互的界面。它提供了一些简单易用的工具…

HDSF 简介

目录 一、HDFS 的设计特点是 二、什么零拷贝 2.1 传统情况&#xff1a; 2.2 零拷贝技术&#xff1a; 三、什么是DMA 四、HDFS 的关键元素 五、HDFS 运行原理 六、HDFS 数据合并原理 七、HDFS 写的原理 八、HDFS 读的原理 九、分块存储 十、 安全模式 十一、 MapRedu…

如何使用微服务架构?使用过程需要注意什么?

一、使用微服务架构的规范 1.1 服务拆分 微服务的服务拆分是根据业务领域和业务功能来划分的&#xff0c;目的是将复杂的单体应用程序分解为小型、自治的服务&#xff0c;每个服务都专注于处理一个特定的业务领域或功能。 以下是微服务拆分的一些常见策略&#xff1a; 领域…

JavaEE——volatile、wait、notify三个关键字的解释

文章目录一、volatile和内存可见性1.解释内存可见性问题2. volatile 的使用与相关问题二、wait 和 notify1.wait 方法2.notify() 方法3. 关于 notifyAll() 方法4. wait 和 sleep 之间的简单比较一、volatile和内存可见性 前面的文章&#xff0c;我们已经提及到了内存可见性问题…

硬件设计--stm32自动下载电路设计

1 参考博客&#xff1a; 1、Stm32 一键下载电路详解 2、启动模式&#xff0c;BOOT0和BOOT1详解 3、STM32自动ISP电路设计 4、STM32 USB接口 一键下载电路详解与过程分析 2 下载软件分享&#xff1a; 参考博客&#xff1a;FlyMcu - 用于STM32芯片ISP串口程序一键下载的免费软…

【速记】Postgresql中几个ResourceOwner的含义

几个ResourceOwner的含义 总结下几个resowner的含义&#xff1a; 事务结构内的resowner&#xff1a;TransactionState→curTransactionOwner 含义&#xff1a;跟随事务结构体创建&#xff0c;会申请内存&#xff0c;跟随事务结构释放。每层事务都有自己的curTransactionOwner…

Vivado 下按键实验

Vivado下按键实验 实验原理 PL通过按键的开关状态控制led的亮灭&#xff0c;按键按下的时候灯亮&#xff0c;按键未按下的时候灯灭。 这里的描述有些问题&#xff0c;PL_LED1为高的时候&#xff0c;LED两端的电压都为高&#xff0c;灯应该是不亮的&#xff0c;所以按照下面实…

口令暴力破解--Ftp协议暴力破解与Ssh协议暴力破解

Ftp协议暴力破解 FTP服务检测 FTP服务 FTP是一种文件传输协议&#xff0c; FTP服务默认端口为21。利用FTP服务器可以在本地主机和远程主机间进行文件传输。当FTP没有配置好安全控制&#xff0c;如对登录的源地址及密码尝试次数做限制&#xff0c;那么就会存在暴力破解可能。…

uniapp - 实现车牌号键盘与格子间隔显示组件,汽车牌照录入支持自定义样式、新能源等(附带组件完整源码,开箱即用,稍微改改就能用)

效果图 uniapp 全平台兼容,车牌号键盘输入、分格显示功能示例源码,注释很多! 可以直接复制一下,然后自己改改样式或功能就能使了。 示例源码 复制,运行。 &

基于神经网络的协同过滤-NCF

目录 1、摘要 2、引言 2.1协同过滤 2.2矩阵分解 3.准备工作 3.1学习隐性数据 3.2矩阵分解 ​3.3神经协同过滤 3.4广义矩阵分解 3.5多层感知器 3.6GMF和MLP的融合-NeuMF(神经矩阵分解) 4.总结 1、摘要 尽管最近的一些工作已经把深度学习运用到了推荐中&#xff0…

【mysql性能调优 • 一】mysql企业级安装部署(保姆级别教程)

前言 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDBMS (Relational Database Management System&#xff0c;关系…

k8s 认证基础

0x00 前言 要想研究一个东西是不是存在安全问题&#xff0c;那么就要知道这个东西是什么&#xff0c;怎么用的&#xff0c;如何认证&#xff0c;认证方式等问题&#xff0c;了解这些才能更好的去解释学习安全问题。 0x01 访问控制 首先是k8s用户k8s用户分为service account以…

涨点技巧:Yolov5/Yolov7引入CVPR2023 Demystify Transformers Convolutions ,提升小目标检测精度

Demystify Transformers & Convolutions in Modern Image Deep Networks 论文:https://arxiv.org/pdf/2211.05781.pdf 视觉转换器最近的成功激发了一系列具有新颖特征转换范例的视觉主干,这些范例报告了稳定的性能增益。尽管新颖的特征转换设计通常被认为是收益的来源,…