力扣 53. 最大子数组和(C语言+分治递归、动态规划)

news2025/2/25 11:25:53

1. 题目

        给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组 是数组中的一个连续部分。

2. 输入输出样例

        示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

        示例 2:

输入:nums = [1]
输出:1

        示例 3:

输入:nums = [5,4,-1,7,8]
输出:23

3. 解题思想

(1)分治递归

        分治法的核心部分。一个整数数组 nums,以及左边界 l 和右边界 r。通过递归的方式将数组划分成更小的子数组,分别找到左半部分、右半部分以及跨越中间位置的子数组的最大和。具体步骤如下:

  • 当左边界等于右边界时,表示只有一个元素,直接返回该元素作为最大子数组和。
  • 计算中间位置,将数组分成左半部分和右半部分。
  • 分别递归调用来找到左半部分和右半部分的最大子数组和。
  • 计算跨越中间位置的最大子数组和,通过两个循环分别向左和向右遍历,找到最大的左半部分和最大的右半部分。
  • 最后,通过比较左半部分、右半部分和跨越中间的子数组和,返回其中的最大值。

 

(2)动态规划

         动态规划算法通过迭代遍历输入数组,维护一个额外的数组 dp 来记录截止到每个位置的最大连续子数组和,并利用一个变量 max_num 实时更新全局最大子数组和的值。

        算法的核心思想在于,通过比较当前元素和前一个元素的最大子数组和是否大于零,来决定是否将当前元素加入前一个子数组或者从当前元素重新开始形成子数组。最终,返回 max_num 作为最大子数组和的解。

  • 初始化dp:dp[i]表示前i个元素最大的连续子数组和
  • 状态转移:如果dp[i-1] > 0, dp[i] = dp[i-1] + nums[i],否则dp[i] = nums[i](分类讨论)
  • 初始换状态:dp[0] = nums[0]
  • 最优解:max(dp)
开始

初始化:
- 数组 dp,大小为 numsSize,用于存储前 i 个元素的最大连续子数组和
- 变量 max_num,用于记录全局最大子数组和
- 将 dp[0] 设置为 nums[0]
- 将 max_num 设置为 nums[0]

遍历数组:
对于 i 从 1 到 numsSize-1:
    如果 dp[i-1] 大于 0:
        - 更新 dp[i] 为 dp[i-1] + nums[i]
    否则:
        - 更新 dp[i] 为 nums[i]
    
    更新 max_num 为 dp[i] 和 max_num 之间的较大值

结束

返回 max_num 作为最大子数组和的解

4. 代码实现

(1)分治递归

// 求三个整数中的最大值
int maxz(int a, int b, int c) {
    // 注意这里等于时的判断
    if (a >= b && a >= c) {
        return a;
    }
    if (b >= a && b >= c) {
        return b;
    }
    return c;
}

// 使用分治法来找到最大子数组和
int maxarry(int* nums, int l, int r) {
    // 当只有一个元素时,直接返回该元素
    if (l == r) {
        return nums[l];
    } 
    // 划分数组的中间位置
    int mid = (l + r) / 2;
    // 分别找到左半部分和右半部分的最大子数组和
    int maxl = maxarry(nums, l, mid);
    int maxr = maxarry(nums, mid + 1, r);
    
    // 计算跨越中间位置的最大子数组和
    int i = mid - 1, j = mid, addl = 0, addr = 0, max1 = 0, max2 = nums[mid];
    for (; i >= l; i--) {
        addl += nums[i];
        if (addl > max1) {
            max1 = addl;
        }
    }
    for (; j <= r; j++) {
        addr += nums[j];
        if (addr > max2) {
            max2 = addr;
        }
    }
    int maxm = max1 + max2;
    // 返回左半部分、右半部分和跨越中间的最大子数组和中的最大值
    return maxz(maxl, maxr, maxm);
}

// 主函数,用于调用 maxarry 函数来解决最大子数组和问题
int maxSubArray(int* nums, int numsSize) {
    // 分治法求解最大子数组和
    return maxarry(nums, 0, numsSize - 1);
}

(2)动态规划

// 定义一个函数,用于返回两个整数中的较大值
int max_(int a, int b) {
    if (a <= b) {
        return b;
    }
    return a;
}

// 使用动态规划解决最大子数组和问题
int maxSubArray(int* nums, int numsSize) {
    // 如果数组只有一个元素,直接返回该元素
    if (numsSize == 1) {
        return nums[0];
    }
    
    int n = numsSize;
    
    // 初始化一个数组 dp,dp[i] 表示前 i 个元素的最大连续子数组和
    int dp[n];
    dp[0] = nums[0];
    
    // 初始化最大子数组和为第一个元素
    int max_num = nums[0];
    
    // 开始状态转移
    for (int i = 1; i < n; i++) {
        // 如果 dp[i-1] 大于 0,则更新 dp[i] 为 dp[i-1] + nums[i]
        // 否则,从当前位置重新开始计算子数组和,即 dp[i] = nums[i]
        if (dp[i - 1] > 0) {
            dp[i] = dp[i - 1] + nums[i];
        } else {
            dp[i] = nums[i];
        }
        
        // 更新最大子数组和
        max_num = max_(max_num, dp[i]);
    }

    // 返回最大子数组和
    return max_num;
}

5. 复杂度分析

(1)分治递归

  1. 时间复杂度分析:

  2. maxz 函数的时间复杂度是 O(1),因为它只执行了一系列常数时间的比较操作。

  3. maxarry 函数是递归的,每次将数组分成两半,然后再合并结果。递归树的高度为 log₂(n),其中 n 是输入数组的大小。在每个递归层级,我们都要遍历一次数组来计算跨越中间位置的最大子数组和,这需要 O(n) 的时间。因此,maxarry 函数的总时间复杂度为 O(n log₂(n))。

总的时间复杂度是 maxarry 函数的时间复杂度,即 O(n log₂(n))。

  • maxSubArray 函数中的循环遍历整个数组一次,需要 O(n) 的时间。

空间复杂度分析:

  1. maxz 函数的空间复杂度是 O(1),因为它没有使用额外的数据结构。

  2. maxarry 函数中的递归调用会使用一些额外的栈空间,但这个空间占用是由递归树的深度决定的,最坏情况下为 O(log₂(n))。

  3. maxarry 函数中使用了一个额外的数组 dp,其大小与输入数组相同,因此空间复杂度为 O(n)。

  4. maxSubArray 函数中的额外空间只包括了几个整数变量,因此空间复杂度是 O(1)。

        综合考虑时间和空间复杂度,时间复杂度是 O(n log₂(n)),空间复杂度是 O(n)。 

(2)动态规划

时间复杂度分析:

  1. 初始化 dp 数组需要 O(n) 的时间,其中 n 是输入数组的大小。

  2. 循环遍历输入数组一次,从第二个元素开始进行状态转移,每个元素的状态转移操作都需要 O(1) 的时间。因此,状态转移的时间复杂度是 O(n)。

总的时间复杂度是初始化时间和状态转移时间的总和,即 O(n) + O(n) = O(n)。

空间复杂度分析:

  1. 需要一个额外的整数数组 dp 来存储前 i 个元素的最大连续子数组和,这个数组的大小与输入数组相同,因此空间复杂度为 O(n)。

  2. 需要几个整数变量来维护当前最大子数组和,这些变量的空间占用是常数级别的,因此可以忽略不计。

总的空间复杂度主要由 dp 数组的空间占用决定,为 O(n)。

        综上所述,动态规划算法的时间复杂度是 O(n),空间复杂度也是 O(n)。它具有线性时间复杂度,适用于解决最大子数组和问题,并且需要额外的线性空间来存储中间结果。

53. 最大子数组和 - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/maximum-subarray/

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

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

相关文章

java进阶-第8章-IO流

一、File类 概念&#xff1a;代表物理盘符中的一个文件或者文件夹。 常见方法&#xff1a; 方法名描述createNewFile()创建一个新文件。mkdir()创建一个新目录。delete()删除文件或空目录。exists()判断File对象所对象所代表的对象是否存在。getAbsolutePath()获取文件的绝对…

最新 SpringCloud微服务技术栈实战教程 微服务保护 分布式事务 课后练习等

SpringCloud微服务技术栈实战教程&#xff0c;涵盖springcloud微服务架构Nacos配置中心分布式服务等 SpringCloud及SpringCloudAlibaba是目前最流行的微服务技术栈。但大家学习起来的感受就是组件很多&#xff0c;不知道该如何应用。这套《微服务实战课》从一个单体项目入手&am…

【Python】下载和安装

【Python】下载和安装 下载 进入 Python官网&#xff0c;下载最新版本&#xff0c;如下图所示&#xff1a; 如果需要下载其他版本&#xff0c;请下滑该页面&#xff0c;找到如下位置&#xff0c;选择需要的版本进行下载&#xff08;以3.8.10为例&#xff09;&#xff1a; 点击…

运行软件找不到mfc140u.dll怎么解决,mfc140u.dll是什么文件

"找不到 mfc140u.dll"是一条错误信息&#xff0c;表示您的计算机上缺少一个名为 mfc140u.dll 的动态链接库&#xff08;DLL&#xff09;文件。这个文件通常与 Microsoft Visual C Redistributable 相关。Mfc140u.dll 是 Microsoft 基础类库&#xff08;MFC&#xff0…

当 FineReport 遇见 CnosDB

随着大数据和物联网应用的快速发展&#xff0c;时序数据库成为了一种关键的数据存储和分析工具。而 FineReport 作为一款流行的商业智能工具&#xff0c;与时序数据库 CnosDB 的集成可以为企业提供更强大的数据分析和可视化功能。本博客将介绍如何将 FineReport 与 CnosDB 集成…

CSS点击切换或隐藏盒子的卷起、展开效果

<template><div class"main"><el-button click"onCllick">切换</el-button><transition name"slideDown"><div class"info" v-if"isShow">1111</div></transition></di…

云数据库保护需要注意哪些事项?

云数据库保护是在云计算环境中对数据库进行保护和安全管理的重要措施。随着云计算的普及和应用&#xff0c;云数据库的保护也变得尤为重要。以下是安策分享的关于云数据库保护需要注意的一些事项。 云数据库的访问控制是保护数据库的首要任务。只有授权的用户或应用程序才能访问…

win11系统下,将WSL2从系统盘(C盘)迁移到迁移到数据盘(D盘)

WSL2迁移磁盘 网上的一些方法 今天希望把WSL迁移到D盘&#xff0c;原因就是C盘剩余空间太少了&#xff0c;系统有一点卡顿&#xff0c;然后百度了一下迁移的方法&#xff0c;发现真的是八仙过海&#xff0c;各显神通啊&#xff0c;改注册表、exclude为.tar然后重新导入等等&a…

MVCC和BufferPool缓存机制

文章目录 1. MVCC多版本并发控制机制2. BufferPool缓存机制 1. MVCC多版本并发控制机制 Mysql可以在可重复读隔离级别下可以保证事务较高的隔离性&#xff0c;这个隔离性是由MVCC机制来保证的&#xff0c;对一行数据的读和写两个操作默认是不会通过加锁互斥来保证隔离性&#…

alsa pcm接口之pcm设备的状态STATE

应用和库之间的协作: ALSA pcm api设计使用状态来确定应用程序和库之间的通信阶段,实际的状态可以被决定通过使用snd_pcm_state调用,下面列举出来状态: SND_PCM_STATE_OPEN: 表示pcm设备被打开的状态,使用了snd_pcm_open()之后进入该状态,并且让snd_pcm_hw_params()调用失败后,…

Safran助力dSPACE实现基于GNSS驾驶功能的HIL仿真

概述 世界知名的模拟与验证方案厂商dSPACE借助虹科Safran GNSS模拟器实现了一套基于GNSS的驾驶功能HIL仿真系统&#xff0c;该系统可以用于自动驾驶、车联网、智能座舱等各类汽车行业应用&#xff0c;并具备极大的灵活性与多功能&#xff0c;适用于各类复杂场景测试。 方案介绍…

vscode更改为中文版本

方式一 在扩展里安装chinese插件 方式二 1.Ctrl&#xff0b; Shift &#xff0b;P&#xff08;commandshiftP&#xff09; 2.输入Configure display Language 3.选择zh-cn 这时候vscode会提示需要重启&#xff0c;点击restart重启vscode&#xff0c;重启后vscode就会显示中…

找不到msvcp140_1.dll怎么办,快速解决msvcp140_1.dll问题的方法分享

在日常使用计算机的过程中&#xff0c;经常会遇到一些程序无法正常运行的问题&#xff0c;其中最常见的就是“msvcp140_1.dll丢失”。这是一个典型的DLL文件丢失问题&#xff0c;但背后的原因却往往并不简单。通过深入研究这个问题&#xff0c;我对其有了更深入的理解。 首先&a…

【沐风老师】3DMAX彩灯串灯生成器使用方法详解

3DMAX彩灯串灯生成器使用教程 3DMAX彩灯串灯生成器&#xff0c;可以让你毫不费力地从场景中选定的线图形创建令人惊叹的串灯模型。可以在线条中单独生成灯泡和电线&#xff0c;有九种不同类型的灯泡可供用户选择&#xff0c;以实现各种照明效果和装饰。该工具具有一系列可自定义…

漏洞复现-易思无人值守智能物流文件上传

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

Rust Http 性能测试框架/工具

在Rust中&#xff0c;有几个常用的性能测试框架和工具可用于对HTTP性能进行测试。以下是其中一些&#xff1a; 1、Criterion&#xff1a;Criterion是一个通用的性能测试框架&#xff0c;可以用于测试各种类型的代码性能&#xff0c;包括HTTP性能。你可以使用Criterion来编写和运…

pnpm、npm、yarn 包管理工具『优劣对比』及『环境迁移』

前言 博主在开发前端网站的时候&#xff0c;发现随着开发的项目的逐渐增多&#xff0c;安装的依赖包越来越臃肿&#xff0c;依赖包的安装速度也是非常越来越慢&#xff0c;多项目开发管理也是比较麻烦。之前我就了解过 pnpm&#xff0c;但是当时担心更换包管理环境可能会出现的…

在微信小程序中如何引入iconfont

目录 前言iconfont 介绍iconfont 组建图标库并下载1. 通过 iconfont 可组建自己的图标库2. 项目设置&#xff1a;生成base64格式的字体3. 下载至本地4. 解压备用 将 iconfont 添加到小程序中1. 将css该名称wxss2. 将文件复制到font目录3. 在app.wxss文件中引入iconfont文件 在小…

Vue中如何进行分布式日志收集与日志分析(如ELK Stack)

在Vue中实现分布式日志收集与日志分析&#xff08;使用ELK Stack&#xff09; 日志收集和分析在现代应用程序中是至关重要的&#xff0c;它们可以帮助开发人员监视和诊断应用程序的行为&#xff0c;从而提高应用程序的稳定性和性能。ELK Stack&#xff08;Elasticsearch、Logs…

矩阵的相似性度量的常用方法

矩阵的相似性度量的常用方法 1&#xff0c;欧氏距离 欧式距离是最易于理解的一种距离计算方法&#xff0c;源自欧式空间中两点间的距离公式。 (1)二维平面上的点 a ( x 1 , y 1 ) a(x_1,y_1) a(x1​,y1​)和点 b ( x 2 , y 2 ) b(x_2,y_2) b(x2​,y2​)的欧式距离为 d ( x …