力扣力扣力:53.最大子数组和

题目:

首先需要说明的是这道题可以用很多方法解决,这里先采取动态规划的方法,等后面再遇到别的方法的时候继续说明其他解法。另外这道题可以是由很多实际问题抽象提炼出来的,例如nums是股票价格,问第几天买入卖出利润最大等等,由这个模型可以延伸出很多实际问题,大家做题的时候要意识到是同一个模型。

既然是动态规划,那么还是老样子分为五步走:

1.状态表示

首先根据经验我们先定义成以i位置为结尾位置状态,又由于题目要求最大的字数组,那么自然的就定义成以i位置为结尾的最大字数组的和

2.状态转移方程

我们先对以i位置为结尾的字数组进行一个分类,由于可能会出现只有一个i位置元素的情况,所以我们单独讨论这种情况。

情况1:只有i位置一个元素,所以和就自然为i位置的值

情况2:除了i位置元素以外前面还有别的元素,但是当我计算前面元素的最大和的时候就可以调用dpi-1了,所以这个表达式就已经出来了

dpi=max(dpi−1+numsi,numsi)

3.初始化

在这道题中,我们介绍一种比较方便写代码的初始化方式。在解码方式那道题中我们初始化的时候情况太多了,我们需要写很多个if判断语句,但是在循环过程里面又复用了同样的语句,因此我们想着能不能合并起来只写一次。答案是可以的,就像链表里面的头节点一样,我们这里也定义一个虚拟节点,这样前面的初始化就会合并到循环里面一并初始化掉了。

但是这样定义有两个注意事项:

1.虚拟节点的值要保证后面的原来数组的初始化正确

2.下标由于往后面都挪动了一位,需要注意映射关系的改变

由于原来的dp0现在往后挪动一位之后变成了dp1,所以根据上面的状态转移方程可以得到:dp1=max(dp0+nums0,nums0),而dp1位置相当于只有一个元素,所以最大和自然就是num0,所以这里为了保证dp1等于num0,这里dp0填上0就可以了

4.填表顺序

由于需要i-1的值所以只能是从前往后填从左往右

5.返回值

这里需要注意的是返回的不一定是dp表最后一个元素,因为最大字数组和不一定出现在最后,就像题目给出的例子一样,是可能出现在中间的,所以返回的应该是dp表里面的最大值。

再分析完之后,下面给出实现:

复制代码
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        //1.创建dp表
        //2.初始化
        //3.填表
        //4.返回结果
        int n = nums.size();
        vector<int> dp(n+1);//这里由于有虚拟节点的存在所以多加1
        int ret = INT_MIN;//保存表中最大值
        for(int i = 1;i<=n;i++)
        {
            dp[i] = max(nums[i-1],dp[i-1]+nums[i-1]);
            ret = max(ret,dp[i]);
        }
        return ret;
    }
};

需要注意的是由于我们多定义了一个虚拟节点所以,这里我们要找的原始nums数组下标要-1,另外定义储存最大值的变量最好定义成INT_MIN,如果 ret 的初始值是 0 或其他较小的值,那么在所有 dp[i] 都小于这个初始值的情况下(例如数组全是负数的情况),ret 会保留错误的值。

最后给出一个具体的例子说明完整的循环过程:

假设我们有 nums = [1, -2, 3, 5]。

  1. 初始化:

    • n = 4,因为 nums 有 4 个元素。

    • dp 的大小为 n+1 = 5,即 dp 的索引范围是 [0, 4],其中 dp[0] 是一个虚拟节点,不参与计算。

  2. 填表过程:

    • i = 1:

      • dp[1] = max(nums[0], dp[0] + nums[0]) = max(1, 0 + 1) = 1

      • ret = max(INT_MIN, dp[1]) = 1

    • i = 2:

      • dp[2] = max(nums[1], dp[1] + nums[1]) = max(-2, 1 - 2) = -1

      • ret = max(1, dp[2]) = 1

    • i = 3:

      • dp[3] = max(nums[2], dp[2] + nums[2]) = max(3, -1 + 3) = 3

      • ret = max(1, dp[3]) = 3

    • i = 4:

      • dp[4] = max(nums[3], dp[3] + nums[3]) = max(5, 3 + 5) = 8

      • ret = max(3, dp[4]) = 8

最终得到 ret = 8,即 nums 的最大子数组和。

相关推荐
yi0116 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
YangYang9YangYan7 小时前
2027 秋招|数据科学与大数据技术面试项目价值回答思路,告别纯代码描述
大数据·面试·职场和发展
灯澜忆梦9 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下9 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J9 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛9 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有10 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu11111110 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode
黄金龙PLUS10 小时前
如何基于置换算法来设计对称加密算法
算法·网络安全·密码学·哈希算法·同态加密
不会就选b10 小时前
算法日常・每日刷题--<动态规划>14
算法