《算法题讲解指南:动态规划算法--子数组系列》--23.等差数列划分,24.最长湍流子数组

🔥小叶-duck个人主页

❄️个人专栏《Data-Structure-Learning》《C++入门到进阶&自我学习过程记录》
《算法题讲解指南》--优选算法
《算法题讲解指南》--递归、搜索与回溯算法
《算法题讲解指南》--动态规划算法

未择之路,不须回头
已择之路,纵是荆棘遍野,亦作花海遨游


目录

23.等差数列划分

题目链接:

题目描述:

题目示例:

解法(动态规划):

算法思路:

C++算法代码:

算法总结及流程解析:

24.最长湍流子数组

题目链接:

题目描述:

题目示例:

解法(动态规划):

算法思路:

C++算法代码:

算法总结及流程解析:

结束语


23.等差数列划分

题目链接:

413. 等差数列划分 - 力扣(LeetCode)

题目描述:

题目示例:

解法(动态规划):

算法思路:

1.状态表示:

由于我们的研究对象是「一段连续的区间」,如果我们状态表示定义成0,i区间内一共有多少等差数列,那么我们在分析dpi的状态转移时,会无从下手,因为我们不清楚前面那么多的「等差数列都在什么位置」。所以说,我们定义的状态表示必须让等差数列「有迹可循」,让状态转移的时候能找到「大部队」。因此,我们可以「固定死等差数列的结尾」,定义下面的状态表示:

dpi 表示:必须「以i位置的元素为结尾」的等差数列有多少种。

2.状态转移方程:

我们需要了解一下等差数列的性质:如果abc三个数成等差数列,这时候来了一个d,其中bcd也能构成一个等差数列,那么abcd四个数能够成等差序列吗?答案是:显然的。因为他们之间相邻两个元素之间的差值都是一样的。有了这个理解,我们就可以转而分析我们的状态转移方程了。

对于dpi位置的元素numsi,会与前面的两个元素有下面两种情况:

i.numsi-2,numsi- 1,numsi三个元素不能构成等差数列:那么以numsi为结尾的等差数列就不存在,此时dpi=;

ii.numsi- 2,numsi- 1,numsi三个元素可以构成等差数列:那么以numsi-1为结尾的所有等差数列后面填上一个 numsi也是一个等差数列,此时dpi=dpi-1 。但是,因为numsi-2,numsi-1,numsi三者又能构成一个新的等差数列,因此要在之前的基础上再添上一个等差数列,于是dpi= dpi- 1 + 1。

综上所述:状态转移方程为:

当:numsi-2 + numsi != 2 * numsi - 1 时, dpi = 0

当:numsi -2 + numsi ==2 * numsi - 1 时,dpi= 1 + dpi-1

3.初始化:

由于需要用到前两个位置的元素,但是前两个位置的元素又无法构成等差数列,因此dp0 = dp1 = 0。

4.填表顺序:

毫无疑问是「从左往右」。

5.返回值:

因为我们要的是所有的等差数列的个数,因此需要返回整个 dp表里面的元素之和。

C++算法代码:

cpp 复制代码
class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& nums) 
    {
        int n = nums.size();
        if(n == 1 || n == 2)
        {
            return 0;
        }
        vector<int> dp(n);
        dp[0] = dp[1] = 0;

        for(int i = 2; i < n; i++)
        {
            if(nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2])
            {
                dp[i] = dp[i - 1] + 1;
            }
            else
            {
                dp[i] = 0;
            }
        }
        int ret = 0;
        for(int i = 0; i < n; i++)
        {
            ret += dp[i];
        }
        return ret;
    }
};

算法总结及流程解析:

24.最长湍流子数组

题目链接:

978. 最长湍流子数组 - 力扣(LeetCode)

题目描述:

题目示例:

解法(动态规划):

算法思路:

1.状态表示:

我们先尝试定义状态表示为:

dpi表示「以i位置为结尾的最长湍流数组的长度」。

但是,问题来了,如果状态表示这样定义的话,以i位置为结尾的最长湍流数组的长度我们没法从之前的状态推导出来。因为我们不知道前一个最长湍流数组的结尾处是递增的,还是递减的。因

此,我们需要状态表示能表示多一点的信息:要能让我们知道这一个最长湍流数组的结尾是「递

增」的还是「递减」的。

因此需要两个dp表:

fi表示:以i位置元素为结尾的所有子数组中,最后呈现「上升状态」下的最长湍流数组的长度;

gi表示:以i位置元素为结尾的所有子数组中,最后呈现「下降状态」下的最长湍流数组的长度。

2.状态转移方程:

对于i位置的元素arri,有下面两种情况:

i.arri>arri-1:如果i位置的元素比i-1位置的元素大,说明接下来应该去找i -1 位置结尾,并且i-1 位置元素比前一个元素小的序列,那就是gi-1。更新 fi位置的值:fi=gi-1+ 1;

ii.arri< arri-1:如果i位置的元素比i-1 位置的元素小,说明接下来应该去找i- 1 位置结尾,并且i-1 位置元素比前一个元素大的序列,那就是fi-1。更新 gi位置的值:gi = fi-1 + 1 ;

iii.arri==arri -1:不构成湍流数组。

3.初始化:

所有的元素「单独」都能构成一个湍流数组,因此可以将dp表内所有元素初始化为1。

由于用到前面的状态,因此我们循环的时候从第二个位置开始即可。

4.填表顺序:

毫无疑问是「从左往右,两个表一起填」。

5.返回值:

应该返回「两个dp表里面的最大值」,我们可以在填表的时候,顺便更新一个最大值。

C++算法代码:

cpp 复制代码
class Solution {
public:
    int maxTurbulenceSize(vector<int>& arr) 
    {
        int n = arr.size();
        if(n == 1)
        {
            return 1;
        }
        vector<int> dp(n);
        dp[0] = 1;
        dp[1] = arr[0] == arr[1] ? 1 : 2;
        for(int i = 2; i < n; i++)
        {
            if(arr[i] > arr[i - 1])
            {
                dp[i] = arr[i - 1] < arr[i - 2] ? dp[i - 1] + 1 : 2;
            }
            else if(arr[i] < arr[i - 1])
            {
                dp[i] = arr[i - 1] > arr[i - 2] ? dp[i - 1] + 1 : 2;
            }
            else
            {
                dp[i] = 1;
            }
        }    
        int ret = INT_MIN;
        for(int i = 0; i < n; i++)
        {
            ret = max(ret, dp[i]);
        }
        return ret;
    }
};

算法总结及流程解析:

结束语

到此,23.等差数列划分,24.最长湍流子数组 这两道算法题就讲解完了。等差数列划分问题:通过定义dpi表示以i结尾的等差子数组数量,利用相邻元素差值关系进行状态转移;最长湍流子数组问题:采用双DP数组分别记录上升和下降状态的最长子数组长度,根据元素大小关系进行状态更新。希望大家能有所收获!

相关推荐
黄敬峰2 小时前
深入理解算法核心:从递归思想、数组扁平化到快速排序
算法
得物技术3 小时前
从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理
人工智能·算法·架构
AI小老六6 小时前
SkillOpt 架构拆解:把 Skill 文本当参数,用执行轨迹训练 Agent
后端·算法·ai编程
胡萝卜术7 小时前
从“分数打架”到“排名投票”:为什么你的ChatBI必须用RRF?
算法·设计模式·面试
Asize8 小时前
初识DFS 与 BFS:递归、队列与图遍历
算法
罗西的思考21 小时前
机器人 / 强化学习】HIL-SERL:人类在环驱动的具身智能进化框架
人工智能·算法·机器学习
美团技术团队1 天前
LongCat 开源 VitaBench 2.0:长期动态智能体基准新标杆
人工智能·算法
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
To_OC2 天前
LC 207 课程表:刚学图论那会儿,我连这是拓扑排序都没看出来
javascript·算法·leetcode
To_OC2 天前
LC 208 实现 Trie 前缀树:曾被名字劝退,写完发现是送分题
javascript·算法·leetcode