[动态规划]最长锯齿子序列

本文介绍了一种解决最长锯齿子序列问题的动态规划策略。通过定义两个状态dp[i][1]表示以第i个数结尾的最长锯齿子序列长度,dp[i][2]表示其增减趋势,作者详细阐述了状态转移方程,并给出了C++代码实现。最终遍历dp数组找到最长锯齿子序列的长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天给大家讲最长锯齿子序列

在这里插入图片描述

思路

这个题目是我中学考试比赛题目 不知道为啥我没做对…

这个题目一看 就知道是一个线性dpdpdp
首先 我们先定义状态设dp[i][1]dp[i][1]dp[i][1]表示以第iii个数结尾的最长锯齿子序列 初始值即dp[1][1]=1dp[1][1]=1dp[1][1]=1
接着就是状态转移 我们知道 如果在第iii个数以前的某个数jjj 满足第iii个数加入这个以jjj结尾的最长锯齿子序列是合法的时候 dp[i][1]=max(dp[i][1],dp[j][1]+1)dp[i][1]=max(dp[i][1],dp[j][1]+1)dp[i][1]=max(dp[i][1],dp[j][1]+1)
现在最重要的问题就是 如何判断第iii个数加入这个数列时 这个数列是否是合法的。
我们再开一维 设dp[i][2]dp[i][2]dp[i][2]表示以第iii个数字结尾的最长锯齿子序列中最后一个数减倒数第二个数的差是正还是负 如果是正,dp[i][2]=1dp[i][2]=1dp[i][2]=1;如果是负dp[i][2]=−1dp[i][2]=-1dp[i][2]=1 则当第iii个数加入以第jjj个数结尾的最长锯齿子序列时 让a[i]−a[j]a[i]-a[j]a[i]a[j]的值的正负与dp[j][2]dp[j][2]dp[j][2]的正负值相反 这个数列就是合法的。
记得注意一下 就是如果数列合法 且dp[j][1]>dp[i][1]dp[j][1]>dp[i][1]dp[j][1]>dp[i][1]时 我们先标记一下a[i]−a[j]a[i]-a[j]a[i]a[j]的正负值 最后jjj这一层循环完之后 dp[i][2]dp[i][2]dp[i][2]就等于这个标记的正负。

代码

#include<cstdio>
#include<iostream>
using namespace std;
int dp[10001][3];
int a[10001];
int n;
int ans;
int main()
{
    freopen("sawtooth.in","r",stdin);
    freopen("sawtooth.out","w",stdout);
    //文件输入输出
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    scanf("%d",&a[i]);
    //输入
    dp[1][1]=1;
    if(a[2]-a[1]>0)
    dp[1][2]=0;
    else
    dp[1][2]=1;
    //dp[1][1]和dp[1][2]的初始值
    for(int i=2;i<=n;++i)
    {
        int bj=0;//标记
        for(int j=1;j<i;++j)
        {
            if(dp[j][2]==0&&a[i]-a[j]>0&&dp[i][1]<dp[j][1]+1)
            {
                dp[i][1]=dp[j][1]+1;
                bj=1;
            }
            if(dp[j][2]==1&&a[i]-a[j]<0&&dp[i][1]<dp[j][1]+1)
            {
                dp[i][1]=dp[j][1]+1;
                bj=0;
            }
            //状态转移
        }
        dp[i][2]=bj;
    }
    for(int i=1;i<=n;++i)
    {
        //cout<<dp[i][1]<<" ";
        ans=max(dp[i][1],ans);//记得遍历一遍 取最大值
    }
    //cout<<endl;
    cout<<ans<<endl;//输出
}
好的,以下是我为您准备的100道Java算法题: 1. 翻转字符串 2. 在数组中查找重复数字 3. 单例模式 4. 冒泡排序 5. 快速排序 6. 选择排序 7. 插入排序 8. 希尔排序 9. 归并排序 10. 桶排序 11. 堆排序 12. 计数排序 13. 二叉树的遍历 14. 二叉树的深度 15. 二叉树的最大深度 16. 二叉树的最小深度 17. 二叉树的最大宽度 18. 二叉树的节点个数 19. 二叉树的叶子节点个数 20. 二叉树的高度 21. 二叉树的镜像 22. 二叉树的中序遍历 23. 二叉树的前序遍历 24. 二叉树的后序遍历 25. 二叉树的层次遍历 26. 二叉树的层次遍历 II 27. 二叉树的锯齿形层次遍历 28. 二叉树的最近公共祖先 29. 二叉树的路径和 30. 二叉树的路径和 II 31. 二叉树的所有路径 32. 二叉树的所有路径 II 33. 二叉树的最长连续序列 34. 二叉树的最深叶子节点的最近公共祖先 35. 二叉树的最大路径和 36. 二叉树的最小深度 II 37. 二叉树的右视图 38. 二分查找 39. 二分查找的变体 40. 二叉搜索树的插入 41. 二叉搜索树的删除 42. 两数之和 43. 三数之和 44. 四数之和 45. 无重复字符的最长子串 46. 最长回文子串 47. 最长公共前缀 48. 字符串中的第一个唯一字符 49. 罗马数字转整数 50. 整数转罗马数字 51. 最大子序和 52. 最长上升子序列 53. 最长公共子序列 54. 最长回文子序列 55. 编辑距离 56. 最长有效括号 57. 最长公共子串 58. 最长连续递增序列 59. 最长连续递减序列 60. 最长连续重复子串 61. 最长重复子数组 62. 最短无序连续子数组 63. 最长的斐波那契子序列的长度 64. 最长等差数列 65. 最长连续子序列 66. 最长湍流子数组 67. 最长子数组的和 68. 最小覆盖子串 69. 最小路径和 70. 最小栈 71. 最大栈 72. 最小栈和最大栈的实现 73. 最小栈和最大栈的查找 74. 最小栈和最大栈的删除 75. 最小栈和最大栈的修改 76. 最小栈和最大栈的插入 77. 最小栈和最大栈的求和 78. 最小栈和最大栈的求差 79. 最小栈和最大栈的求积 80. 最小栈和最大栈的求商 81. 最小栈和最大栈的求余 82. 最小栈和最大栈的排序 83. 最小栈和最大栈的反转 84. 最小栈和最大栈的合并 85. 最小栈和最大栈的交集 86. 最小栈和最大栈的并集 87. 最小栈和最大栈的差集 88. 最小栈和最大栈的对称差 89. 最小栈和最大栈的求最大值 90. 最小栈和最大栈的求最小值 91. 最小栈和最大栈的求中位数 92. 最小栈和最大栈的求平均值 93. 最小栈和最大栈的求方差 94. 最小栈和最大栈的求标准差 95. 最小栈和最大栈的求众数 96. 最小栈和最大栈的求众数 II 97. 最小栈和最大栈的求众数 III 98. 最小栈和最大栈的求众数 IV 99. 最小栈和最大栈的求众数 V 100. 最小栈和最大栈的求众数 VI 希望这些算法题能够对您有所帮助!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值