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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

求最长递增子序列个数——C++

發布時間:2024/1/8 c/c++ 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 求最长递增子序列个数——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]時,有:

  • 如果dp[i] == dp[j] + 1,則count[i] += count[j];
  • 如果dp[i] <?dp[j] + 1,則count[i] = count[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]時,有:

  • 如果dp[i] == dp[j] + 1,則count[i] += count[j];
  • 如果dp[i] <?dp[j] + 1,則count[i] = count[j];
  • 元素下標n01234567
    元素值109253710118
    dp[i](或LIS)11122344
    count12312224

    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++的全部內容,希望文章能夠幫你解決所遇到的問題。

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