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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

动态规划应用--最长递增子序列 LeetCode 300

發(fā)布時間:2024/7/5 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 动态规划应用--最长递增子序列 LeetCode 300 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

文章目錄

    • 1. 問題描述
    • 2. 解題思路
      • 2.1 動態(tài)規(guī)劃
      • 2.2 二分查找

1. 問題描述

有一個數(shù)字序列包含n個不同的數(shù)字,如何求出這個序列中的最長遞增子序列長度?比如2,9,3,6,5,1,7這樣一組數(shù)字序列,它的最長遞增子序列就是2,3,5,7,所以最長遞增子序列的長度是4。
https://leetcode-cn.com/problems/longest-increasing-subsequence/

2. 解題思路

  • 類似題目:
    山谷序列(DP)
    LeetCode 5644. 得到子序列的最少操作次數(shù)(最長上升子序DP nlogn)
    LeetCode 5559. 得到山形數(shù)組的最少刪除次數(shù)(最長上升子序DP nlogn)
    程序員面試金典 - 面試題 17.08. 馬戲團(tuán)人塔(最長上升子序 DP/二分查找)
    LeetCode 354. 俄羅斯套娃信封問題(最長上升子序 DP/二分查找)
    LeetCode 368. 最大整除子集(DP)
    程序員面試金典 - 面試題 08.13. 堆箱子(DP)
    LeetCode 673. 最長遞增子序列的個數(shù)(DP)
    LeetCode 1027. 最長等差數(shù)列(DP)
    LeetCode 5545. 無矛盾的最佳球隊(最大上升子序DP)
    LeetCode 5245. 堆疊長方體的最大高度(排序+最大上升子序DP)

2.1 動態(tài)規(guī)劃

  • 假設(shè)在包含 i-1 下標(biāo)數(shù)字時的最大遞增子序列長度為 maxLen(i-1),那么下標(biāo)為 i 時的 maxLen(i)需要考慮前面所有的狀態(tài),
  • 如果 a[j] < a[i] (0 <= j < i),則 maxlen[i] = max(maxlen[j]+1 | (0 <= j < i));
  • 如果 a[j] >= a[i] (0 <= j < i),則 maxlen[i] = 1;

借一張動圖說明

class Solution { public:int lengthOfLIS(vector<int>& nums) {int n = nums.size();if(n == 0)return 0;int maxlen[n], ans;int i, j;for(i = 0; i < n; ++i)maxlen[i] = 1;//至少為1,自己for(i = 1; i < n; ++i){ans = 1;for(j = 0; j < i; ++j){if(nums[i] > nums[j] && maxlen[j]+1 > ans){ans = maxlen[j]+1;maxlen[i] = ans;} }}for(ans = 1, i = 0; i < n; ++i){if(maxlen[i] > ans)//取最大值ans = maxlen[i];}return ans;} }; class Solution { //2020.3.14 public:int lengthOfLIS(vector<int>& nums) {if(nums.size() == 0)return 0;int i, j, n = nums.size(),maxlen = 1;vector<int> dp(n,1);for(i = 1; i < n; ++i){for(j = i-1; j >= 0; --j){if(nums[i] > nums[j])dp[i] = max(dp[i], dp[j]+1);}maxlen = max(maxlen, dp[i]);}return maxlen;} };

2.2 二分查找

  • 參考官方的解答
  • dp[i] 表示長度為 i+1 的子序的最后一個元素的 最小數(shù)值
  • 遍歷每個 nums[i],找到其在dp數(shù)組中的位置(大于等于 nums[i] 的第一個數(shù)),將他替換成較小的

以輸入序列 [0, 8, 4, 12, 2] 為例:

第一步插入 0,dp = [0]

第二步插入 8,dp = [0, 8]

第三步插入 4,dp = [0, 4]

第四步插入 12,dp = [0, 4, 12]

第五步插入 22,dp = [0, 2, 12]

class Solution { public:int lengthOfLIS(vector<int>& nums) {if(nums.size() == 0)return 0;int i, l, r, n = nums.size(), maxlen = 1, idx;vector<int> dp(n);dp[0] = nums[0];for(i = 1; i < n; ++i)//遍歷每個數(shù){l = 0, r = maxlen-1;idx = bs(dp,l,maxlen,nums[i],maxlen);//二分查找nums[i] 在dp中的位置if(idx == maxlen)//nums[i] 是最大的{dp[idx] = nums[i];maxlen++;}else//不是最大的,更新 dp[i] 里的數(shù)為較小的dp[idx] = min(dp[idx], nums[i]);}return maxlen;} int bs(vector<int> &dp, int l, int r, int& target, int& maxlen){ //二分查找nums[i] 在dp中的位置, 第一個大于等于 nums[i] 的int mid;while(l <= r){mid = l + ((r-l)>>1);if(dp[mid] < target)l = mid+1;else{if(mid == 0 || dp[mid-1] < target)return mid;elser = mid-1;}}return maxlen;//沒有找到,nums[i] 最大,放最后} };
  • 基于上面的想法,直接用 treeset 可以簡化代碼
class Solution { public:int lengthOfLIS(vector<int>& nums) {if(nums.size() == 0)return 0;set<int> s;for(auto& n : nums){if(s.count(n))continue;else{auto it = s.upper_bound(n);//n的上界if(it == s.end())//沒有比我大的s.insert(n);else//有比我大的{s.erase(it);//刪除比我大的s.insert(n);//換成我}}}return s.size();} };

總結(jié)

以上是生活随笔為你收集整理的动态规划应用--最长递增子序列 LeetCode 300的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。