题目:最长上升子序列的长度
如:1 4 -3 -9 5 9 0 //1 4 5 9
如:1,5,2,3,4,6,-5,-9,10,11// 1 2 3 4 6 10 11
子序列 不要求连续,前后关系要和原序列一致
最长递增子序列是非常经典的一个算法问题。看到题目时需注意子序列和子串是并不相同的,子串必须是连续的。所以第一时间想到的也是最无脑的方法----穷举法,似乎不能用了。真的不能用吗?可以,不过需要一些变通。
穷举法
穷举法就是把所有可能出现的情况一个一个例举出来再进行判断。在这题中单纯的循环遍历数组是行不通的,那只能求出最长上升子串。而我们知道子序列是数组的一个子集,那我们例举出该数组所有的子集不就可以了。那么怎么例举的呢?这就需要我们引入一个概念位运算。我们都知道数据存储在计算机中只有两种形式 0 或者 1 ,而我们以 0 或者 1 来指代这个数组的子集中是否含有该元素,0 和 1 所在的位置指代该元素在数组中的位置,然后再进行遍历判断该序列是否为上升序列就行了。
话不多说上代码
#include<stdio.h>
int main()
{
int i,j,t1,t2,n,N;
printf("请输入数组的长度:\n");
scanf("%d",&N);
int a[N]; //这里有些编译器不支持这种写法,直接将值固定就行。
for (i =0; i < N; i++)
scanf("%d",&a[i]);
int max = 1;//存储最长上升子序列的长度
for(j = 1 ; j < (1 <<N); j++ )
{
t1 = t2 = -65535;
//t1 保存当前选中的元素的值
//t2 保存上一个选中的元素的值
n = 0; //上升序列的元素个数
for(i = 0; i <N; i++)
{
if(j & (1 << i)) //判断是否有第 i 位元素
{
t2 = t1;
t1 = a[i];
if(t1 > t2)
{
n ++;
if(n > max)
{
max = n;
}
}
else
{
break;
}
}
}
}
printf("最长上升序列的长度为%d\n",max);
}
但是这种方法的时间复杂度非常高(2N),并且只能判断32位数以下的数组-----int 类型只含有32位。
所以并不推荐使用。