贪心算法例题(二)
摇摆序列问题
1、题目描述
如果连续数字之间的差严格地在正数和负数之间交替,则数字序列称为摆动序列。第一个差(如果存在的话)可能是正数或负数。少于两个元素的序列也是摆动序列。
例如, [1,7,4,9,2,5] 是一个摆动序列,因为差值 (6,-3,5,-7,3) 是正负交替出现的。相反, [1,4,7,2,5] 和 [1,7,4,5,5] 不是摆动序列,第一个序列是因为它的前两个差值都是正数,第二个序列是因为它的最后一个差值为零。
给定一个整数序列,返回作为摆动序列的最长子序列的长度。 通过从原始序列中删除一些(也可以不删除)元素来获得子序列,剩下的元素保持其原始顺序。
2、问题分析
通过数组给定若干个数字,最后程序返回的是最长摇摆子序列。我们首先要搞清楚的是这个摇摆子序列是怎么定义的,题目描述中清晰的告诉我们是通过从原始序列中删除一些(或者不删除)元素的方式获取子序列。那么现在的问题的关键就是使用什么方法判断这个序列是不是摇摆子序列,如果不是的话我们该如何删除,删除哪些元素才能是当前子序列是摇摆子序列。摇摆子序列如果反映在数轴上的话形成的是折线图。但是在这线图中有一些连续上升或者连续下降的节点,我们需要把这些节点删除之后才能摇摆序列。
3、算法思想
贪心思想(当出现连续上升或者连续下降的节点的时候,我们要删除这些节点只保留其中的一个,具体保留哪一个应该是贪心的认为:保留的这个节点会有最大的概率使得下一个节点也是摇摆序列中的节点这样最后求出来的才能是最长摇摆子序列)
1、给定一个整型数组,按照摇摆序列的要求,如果数组的长度小于2,那么这个数组就直接是一个摇摆序列
2、接下来通过状态机转换的方法来解决问题。设置三个状态:BEGIN、UP、DOWN,然后通过当前数字大小和前一个数字大小进行比较确定相比前一个数字是上升状态还是下降状态。
3、如果上一个状态是上升状态,现在这个数字比上一个数字小,这表明当前是下降状态,符合摇摆序列的要求,表示摇摆序列长度的变量值加一;
4、如果上一个状态是下降状态,现在这个数字比上一个数字大,这表明当前是上升状态,符合摇摆序列的要求,表示摇摆序列长度的变量值加一;
5、除了这两种情况之外的其他情况都是不符合摇摆序列要求的,表示摇摆序列长度的变量值加一保持不变。
6、当整个数组循环结束之后返回表示摇摆序列长度的变量值就是当前数组的最长摇摆子序列。
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
static const int up = 1, down = 2, equation = 3;
static int status = equation;
int function(vector<int>& v)
{
int counst = 1;
if (v.size() == 1) return 1;
for (int i = 1;i < v.size();++i)
{
switch (status)
{
case equation:
if (v[i - 1] > v[i])
{
counst++;
status = down;
}
else if (v[i - 1] < v[i]) {
counst++;
status = up;
}
break;
case up:
if (v[i - 1] > v[i]) {
counst++;
status = down;
}
break;
case down:
if (v[i - 1] < v[i]) {
counst++;
status = up;
}
break;
}
}
return counst;
}
int main()
{
int a[10] = {1,17,5,10,13,15,10,5,16,8};
vector<int> v;
for (int i = 0;i < 10;++i)
{
v.push_back(a[i]);
}
cout << function(v);
}