程式設計題-求最長遞增子序列的數量
阿新 • • 發佈:2019-02-16
最長遞增子序列的數量
- 出處:今日頭條內推一面程式設計題
- 題目:有一個無序陣列,現需要你找到最長的遞增的子序列的個數。
eg1: 1 2 4 3 5
最長的遞增子序列是 1 2 4 5 和 1 2 3 5,所以應輸出2。
eg2:1 1 1 1 1
輸出5,即是5個長度為1 的 1
思路
我們從陣列下標為0開始,0下標時,包含當前位置的最大長度只能是1,並且次數是1,下標為1時,包含1下標的最長遞增序列需要和0位去比較,a[1]> a[0]那麼自然會將長度更新為2,出現的次數賦初值1,若小於或者的等於,那麼包含1下標的字串就是a[1]本身,最長為1,出現次數為1,然後按照這種方式去判斷之後的下標。
這個,很明顯是要用到動態規劃的思路,而且這個不是簡單的DP,但前位置的結果,不單單由他前一位去決定,而是由其前面所有來決定,那麼整理下思路:
用 a[] = 1 2 4 3 5 來舉例。
現在需要一個輔助陣列a_t[2][len(a)]。這個陣列的第一行,存的是以該下標位置的數字作為結束,最長的遞增字串的長度。為何一定要用該位置做結尾,因為我們不清楚,或許當前看來選擇這裡個下標使得字串長度變小,但不確定以後這個長度是否會超過不選擇該下標。陣列第二行,存的是該長度的字串的個數。
那麼最終a_t = {
1,2,3,3,4
1,1,1,1,2
}
即可得知最長字串是4個長度,出現了2次。
#include<stdio.h>
#include<string.h>
int main(void){
int n;
scanf("%d",&n);
int a[n];
int i,j;
for(i = 0;i<n;i++){
scanf("%d",&a[i]);
}
int a_t[2][n];
memset(a_t,0,2*n*4);
a_t[0][0] = 1;
a_t[1][0] = 1;
for(i = 1;i<n;i++){
int max = 1;
int times = 1;
for(j = 0;j<i;j++){
int m = 1;
//m代表當前的長度,最少是1
if(a[i] > a[j]){
m = a_t[0][j] + 1;
//如果當前的這一位比前面的某一位大,則說明會使長度增加
}
else if(a[i] == a[j]){
//相等則不改變最大長度
m = a_t[0][j];
}
//更新最大長度以及最大長度出現的次數
if(m > max){
max = m;
times = 1;
}else if(m == max){
times ++;
}
}
a_t[0][i] = max;
a_t[1][j] = times;
}
/*
用一個二維陣列,第一行為該位置最長可以組成的序列長度,第二行代表該長度的序列個數
*/
for(i = 0;i<2;i++){
for(j = 0;j<n;j++){
printf("%d ",a_t[i][j]);
}
puts("");
}
return 0;
}