今天的算法实验课是关于最长上升子序列的,总结一下。ios
首先须要知道,子串和子序列的概念,咱们以字符子串和字符子序列为例,更为形象,也能顺带着理解字符的子串和子序列:算法
知道了这个,数值的子序列就很好明白了,即用数组成的子序列。这样的话,最长上升子序列也很容易明白了,归根结底仍是子序列,而后子序列中,按照上升顺序排列的最长的就是咱们最长上升子序列了。数组
最长上升子序列(Longest Increasing Subsequence),简称LIS,也有些状况求的是最长非降序子序列,两者区别就是序列中是否能够有相等的数。假设咱们有一个序列bi,当b1 < b2 < … < bS的时候,咱们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),咱们也能够从中获得一些上升的子序列(ai1, ai2, …, aiK),这里1<=i1<i2<…<iK<=N,但必须按照从前到后的顺序。好比,对于序列(1, 7, 3, 5, 9, 4, 8),咱们就会获得一些上升的子序列,如(1,7,9), (3,4,8), (1,3,5,8)等等,而这些子序列中最长的(如子序列(1,3,5,8)),它的长度为4,所以该序列的最长上升子序列长度为4。spa
还有一个很是重要的问题:请你们用集合的观点来理解这些概念,子序列、公共子序列以及最长公共子序列都不惟一,但很显然,对于固定的数组,虽然LIS序列不必定惟一,但LIS的长度是惟一的。再拿咱们刚刚举的栗子来说,给出序列 ( 1, 7, 3, 5, 9, 4, 8),易得最长上升子序列长度为4,这是肯定的,但序列能够为 ( 1, 3, 5, 8 ), 也能够为 ( 1, 3, 5, 9 )。code
输入: 2 3 6 1 7 4 10 8 9ci
设maxlength[i]存储以第i个元素结束的子问题最长上升子序列的长度字符串
子问题(数组的每一位遍历) | maxlength 元素值 |
---|---|
子问题:2 | maxlength[1]=1 初值 |
子问题:2 3 | maxlength[2]= maxlength[1]+1 |
子问题:2 3 6 | maxlength[3]= maxlength[2]+1 |
子问题:2 3 6 1 | maxlength[4]= 1 |
子问题:2 3 6 1 7 | maxlength[5]= maxlength[3]+1 |
子问题:2 3 6 1 7 4 | maxlength[6]= maxlength[2]+1 |
子问题:2 3 6 1 7 4 10 | maxlength[7]= maxlength[5]+1 |
子问题:2 3 6 1 7 4 10 8 | maxlength[8]= maxlength[5]+1 |
子问题:2 3 6 1 7 4 10 8 9 | maxlength[9]= maxlength[8]+1 |
#include <iostream> using namespace std; void LISLength(int a[], int n) { int *maxlength = new int[n]; // 定义一个存储到每一位元素为止的最长子序列长度的动态数组 *(maxlength+0) = 1; // 设置第一个元素的值为1,及最小时为1 int max = 1; // 保存最大最长子序列长度,初始化为1,及最小为1 // 遍历每一位元素,保存到每一位元素前的最长子序列长度 for (int i = 1; i < n; i++) { int max_t = 0; // 初始化每一次的最长子序列长度 // 当前元素与以前元素的比较 for (int j = 0; j < i; j++) { // 当遍历元素大于其前面的此元素,且大于遍历过的最长子序列长度时 if (a[i] > a[j] && *(maxlength+j) > max_t) { max_t = *(maxlength + j); // 更新最长子序列长度 *(maxlength + i) = *(maxlength + j) + 1; // 到该遍历元素的最长子序列长度 } // 当遍历元素小于前面全部的元素时,设置到该遍历元素的最长子序列长度 为 1 else if(max_t == 0 && j == i -1) { *(maxlength + i) = 1; } } // 更新最长子序列长度值 if (*(maxlength + i) > max) max = *(maxlength + i); } cout << "最长子序列长度:" << max << endl; delete[] maxlength; // 销毁动态数组 } int main() { int n = 0; cout << "请输入数组大小:" << endl; cin >> n; int* arr = new int[n]; // 定义动态数组 cout << "请输入数据:" << endl; // 输入数组数据 for (int i = 0; i < n; i++) { cin >> *(arr+i); } LISLength(arr, n); delete[] arr; // 销毁动态数组 return 0; }
效果io