《算法题讲解指南:动态规划算法--子数组系列》--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数组分别记录上升和下降状态的最长子数组长度,根据元素大小关系进行状态更新。希望大家能有所收获!

相关推荐
hope_wisdom6 分钟前
C/C++数据结构之二叉树基础
c语言·数据结构·c++·二叉树
磊 子6 分钟前
STL算法库讲解1
开发语言·c++·算法
8Qi87 分钟前
LeetCode 474:一和零(Ones and Zeroes)—— 题解 ✅
算法·leetcode·职场和发展·动态规划·01背包
stolentime13 分钟前
CF2066D2 Club of Young Aircraft Builders (hard version)题解
c++·算法·动态规划·组合数学
rqtz18 分钟前
【C++】源码编译 Qt5.15.3|Ubuntu22.04 下 ROS 开发环境搭建
开发语言·c++·qt·ros
洛水水18 分钟前
图床项目实现:注册登录 + 文件上传等功能的完善
网络·c++·mysql·图床
一个不知名程序员www18 分钟前
算法学习入门---算法题DAY3
c++·算法
七夜zippoe20 分钟前
DolphinDB向量化计算:高性能数据处理
算法·dolphindb
悠仁さん29 分钟前
哈夫曼树的简单介绍
算法
bIo7lyA8v30 分钟前
算法与数据结构协同优化的设计思想的技术8
数据结构·算法