Spring和SpringBoot有哪些區別
今天的演算法實驗課是關於最長上升子序列的,總結一下。
概念
首先需要知道,子串和子序列的概念,我們以字元子串和字元子序列為例,更為形象,也能順帶著理解字元的子串和子序列:
- 字元子串指的是字串中連續的n個字元,如abcdefg中,ab,cde,fg等都屬於它的字串。
- 字元子序列指的是字串中不一定連續但先後順序一致的n個字元,即可以去掉字串中的部分字元,但不可改變其前後順序。如abcdefg中,acdg,bdf屬於它的子序列,而bac,dbfg則不是,因為它們與字串的字元順序不一致。
知道了這個,數值的子序列就很好明白了,即用陣列成的子序列。這樣的話,最長上升子序列也很容易明白了,歸根結底還是子序列,然後子序列中,按照上升順序排列的最長的就是我們最長上升子序列了。
最長上升子序列(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。
還有一個非常重要的問題:請大家用集合的觀點來理解這些概念,子序列、公共子序列以及最長公共子序列都不唯一,但很顯然,對於固定的陣列,雖然LIS序列不一定唯一,但LIS的長度是唯一的。再拿我們剛剛舉的栗子來講,給出序列 ( 1, 7, 3, 5, 9, 4, 8),易得最長上升子序列長度為4,這是確定的,但序列可以為 ( 1, 3, 5, 8 ), 也可以為 ( 1, 3, 5, 9 )。
例子
輸入: 2 3 6 1 7 4 10 8 9
設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;
}
效果