日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

求最长单调子序列java,单调减子序列(java实现)

發布時間:2025/3/12 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 求最长单调子序列java,单调减子序列(java实现) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目:從一個由N個整數排列組成的整數序列中,自左向右不連續的選出一組整數,可以組成一個單調減小的子序列(如從{68 69 54 64 68 64 70 67 78 62 98 87}中我們可以選取出{69 68 64 62}這個子序列;當然,這里還有很多其他符合條件的子序列)。給定整數序列的長度和整數序列中依次的值,請你求出這個整數序列中“最長的單調減小的子序列的長度”以及“不同但長度都是最長得單調減小的子序列的數量”。

輸入第1行為一個整數N,表示輸入的整數序列的長度(1≤N≤50000)。輸入第2行包括由空格分隔的N個整數(每個整數都在32位長整型范圍內)。

輸出包括一行,為兩個數字,分別為針對給定的整數序列求出的“最長的單調減小的子序列的長度”以及“值不同但長度都是最長得單調減小的子序列的數量”

樣例輸入

12

68 69 54 64 68 64 70 67 78 62 98 87

樣例輸出

4 2

對于這個題,一共有兩個小部分的問題要解決。前一個問題是最長不上升子序列,屬于LIS問題,使用動態規劃解決,后一個問題屬于去重問題。

對于LIS問題,聲明dp[i] 以第i個元素為結尾的子序列的最長的長度。

對第i個元素,與前i-1個元素進行比較:

dp[i] = 1; //當末尾只要一個元素時 長度為1

如果 arr[i] < arr[j]:

如果dp[i] < dp[j] + 1

此時dp[i]的值會被更新為dp[j] + 1

其他情況不做處理

對于去重問題:

“值不同但長度都是最長得單調減小的子序列的數量” 這里說的是:

比如輸入:

6

2 1 2 1 2 1

輸出應為 2 1

2 1 2 1 這兩個是值相同的,所以應該當做一個

使用size[i] 數組去記錄第i元素為結尾時,值不同但長度都是最長得單調減小的子序列的數量

每次在dp更新一遍以后,進行size的更新。

去掉相同值的情況,如果只去關注最后結尾時:

因為每次遍歷都會更新狀態,也就是說如果有相同值的時候 后者會把前者的情況 都會過一遍,所以只要每次更新時保證只取相同值的最后一個出現的元素位置的size[j]即可,也就是最右邊的那個。

對于i元素所構成的最長子序列的前一個元素可能有很多不同值,所以要記錄這些值,并只取最右邊的。

最后size 和 dp都已經生成了最終數組

然后對整個數組進行遍歷, 找出最大序列 且值不同的序列的數量

方法同找單個i位置元素的值不同但長度都是最長得單調減小的子序列的數量 一致

其他說明:

數據較大 使用java中的BigInteger

遍歷找值不同但長度都是最長得單調減小的子序列的數量時 使用倒序查找

代碼:

Scanner read = new Scanner(System.in);

int n = read.nextInt();

long[] arr = new long[n];

long[] dp = new long[n];

BigInteger[] size = new BigInteger[n];

for(int i = 0; i < n; ++i){

arr[i] = read.nextLong();

}

long max = 0;

for(int i = 0; i < n; ++i){

dp[i] = 1;

size[i] = new BigInteger("0");

for(int j = 0; j < i; ++j){

if(arr[j] > arr[i]){

if(dp[j] + 1 > dp[i]){

dp[i] = dp[j] + 1;

}

}

}

if(dp[i] > max){

//更新 最長長度

max = dp[i];

}

// 確定以arr[i]結尾的 子序列中 值不同但長度都是最長得單調減小的子序列的數量

if(dp[i] > 1){//如果 不是只有一個數字的時候

Set sl = new HashSet<>();

for(int j = i - 1; j >= 0; --j){

//從右向左查詢 只查詢第一次遇到的并且是最大長度的 size[i]

// 沒有記錄路徑 通過 arr[j] > arr[i] && dp[j] == dp[i] - 1 來確定是否是前一個轉移

// 遇到相同結尾的情況,更右邊的已經包含了左邊的情況

if(arr[j] > arr[i] && dp[j] == dp[i] - 1 && !sl.contains(arr[j])){

sl.add(arr[j]);//去重

size[i] = size[i].add(size[j]);

}

}

}else{

//只有一個數字是 數量為1

size[i] = new BigInteger("1");

}

}

BigInteger maxBigI = new BigInteger("0");

Set set = new HashSet<>();

//遍歷整個序列 找出最大長度 且值不同的序列的數量

for(int i = n - 1; i >= 0; --i){

if(dp[i] == max && !set.contains(arr[i])){

set.add(arr[i]);

maxBigI = maxBigI.add(size[i]);

}

}

System.out.println(max + " " + maxBigI.toString());

}

總結

以上是生活随笔為你收集整理的求最长单调子序列java,单调减子序列(java实现)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。