求最长递增子序列个数——C++
?聲明:本文原題主要來自力扣,記錄此博客主要是為自己學習總結,不做任何商業等活動!
一、下面是原題描述
給定一個未排序的整數數組,找到最長遞增子序列的個數。
示例 1:
輸入: [1,3,5,4,7]
輸出: 2
解釋: 有兩個最長遞增子序列,分別是 [1, 3, 4, 7] 和[1, 3, 5, 7]。
示例 2:
輸入: [2,2,2,2,2]
輸出: 5
解釋: 最長遞增子序列的長度是1,并且存在5個子序列的長度為1,因此輸出5。
注意:?給定的數組長度不超過 2000 并且結果一定是32位有符號整數。
1.1題目分析
由于上一篇博客已經分析過求最長上升子序列長度——C++的經典LIS問題,該題是求最長增長子序列個數,經過分析,這題也只是經典LIS(Longest Increasing Subsequence)問題的變種,也就是用同樣的LIS框架,區別在于本體需要額外記錄每個最長子序列個數。下面是具體實現思路。
用dp[i]記錄最長子序列長度maxLen,count[i]記錄最長子序列個數,其中i表示數組的元素個數,0 <= i < n;如果求出前dp[i]和count[i]的i-1元素的值,則可以推導出:
dp[i] = max(dp[j]) + 1,滿足條件nums[i] > nums[j],0 =< i < n,0 <=?j?< i - 1;
當nums[i] > nums[j]時,有:
第(1.)需要累加是因為前面遇到一個相同的最長子序列,需要把該子序列也加上。后面第(2.)之所以重新賦值,是因為第一次遇到更長的子序列,故需要更新count[i]最長子序列長度。
當求出全部的count[i]后,需要遍歷找出等于maxLen的所有count[j],然后將這些滿足條件的coount[j]全部相加即為最長子序列長度asn。
動態規劃滿足三個條件:狀態方程、狀態轉移方程、邊界條件,根據分析可知該題滿足條件,下面是分析的表格:
nums = {10, 9, 2, 5, 3, 7, 101, 18}
dp[i] = max(dp[j]) + 1,滿足條件nums[i] > nums[j],0 =< i < n,0 <=?j?< i - 1;
當nums[i] > nums[j]時,有:
| 元素下標n | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 元素值 | 10 | 9 | 2 | 5 | 3 | 7 | 101 | 18 |
| dp[i](或LIS) | 1 | 1 | 1 | 2 | 2 | 3 | 4 | 4 |
| count | 1 | 2 | 3 | 1 | 2 | 2 | 2 | 4 |
1.2代碼實現分析
1.2.1求出dp[i]和count[i]的值
假如nums[i]>nums[j],則更新dp[i]和count[i],更新規則為假如dp[i]<dp[j]+1,dp[i]=dp[j]+1,且count[i]=count[j],著兩條語句是假如有更長最長子序列,則更新dp[i]和count[i],一般如果第一次出現更長最長子序列,count[i]==1,只有在小遍歷第二次遇到該最長子序列時,才會累加count[i]+=count[j],則關鍵實現代碼如下:
for (int i = 0; i < size; ++i) // 求出前面i個dp[i]和count[i]的值 {dp[i] = 1;count[i] = 1;for (int j = 0; j < i; ++j) // 更新dp[i]和count[i]{if (nums[i] > nums[j]){if (dp[i] < dp[j] + 1){dp[i] = dp[j] + 1;count[i] = count[j];}else if (dp[i] == dp[j] + 1){count[i] += count[j];}}}// 根據已求得的dp[i]和count[i],求出asn }1.2.2根據已求得的dp[i]和count[i]求出asn
根據前面已經更新的dp[i]和count[i],求出最長子序列長度asn。即假如有新增最長子序列,則直接更新asn=count[i],否則有相同最長子序列dp[i]==maxLen,則累加所有最長子序列長度asn+=count[i]。關鍵代碼如下:
for (int i = 0; i < size; ++i) // 大遍歷 {dp[i] = 1;count[i] = 1;for (int j = 0; j < i; ++j) // 小遍歷,更新dp[i]和count[i]{// ......}if (dp[i] > maxLen) // 假如有新增最長子序列,則直接更新{maxLen = dp[i];asn = count[i];}else if (dp[i] == maxLen) // 否則有相等最長子序列,則累加所有相同子序列count[i]{asn += count[i];} }1.3完整代碼
class Solution { public:int findNumberOfLIS(vector<int>& nums) {int asn=0, maxLen=1, size = nums.size();vector<int> dp(size, 0), count(size, 0);for(int i=0; i<size; ++i) // 大遍歷{dp[i] = 1;count[i] = 1;for(int j=0; j<i; ++j) // 小遍歷,更新dp[i]和count[i]{if(nums[i] > nums[j]) // 出現更新子序列{if(dp[i] < dp[j] + 1) // 更新最長子序列長度{dp[i] = dp[j] + 1;count[i] = count[j];}else if(dp[i] == dp[j] + 1) // 出現相同最長子序列長度,累加所有相同最長子序列{count[i] += count[j];}}}if(dp[i] > maxLen) // 更新完后找出最長子序列dp[i],大于maxLen則更新,否則累加{maxLen = dp[i];asn = count[i];}else if(dp[i] == maxLen) // 遇到相同最長子序列,需要累加所有相同最長子序列{asn += count[i];}}return asn;} };1.4結果
1.5復雜度分析
由上面代碼實現可知,經過了雙層遍歷,即時間復雜度為O(n^2);申請了n個長度的數組空間,故空間復雜度為O(n)。
總結
以上是生活随笔為你收集整理的求最长递增子序列个数——C++的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干货!STABLE - 一种无监督高鲁棒
- 下一篇: QT安装我i发下载存档问题解决