DP:子序列問題

文章目錄

  • 什么是子序列
    • 子序列的特點
    • 舉例說明
    • 常見問題
  • 關于子序列問題的幾個例題
    • 1.最長遞增子序列
    • 2.擺動序列
    • 3.最長遞增子序列的個數
    • 4.最長數對鏈
    • 5.最長定差子序列
  • 總結

在這里插入圖片描述

什么是子序列

在計算機科學和數學中,子序列(Subsequence)是指從一個序列中刪除一些元素(可以是零個或多個),但不改變其余元素相對順序后形成的新序列。

子序列的特點

元素的相對順序保持不變。
可以刪除零個或多個元素。
一個序列的子序列可以為空序列,即不包含任何元素。

舉例說明

設有序列 S = [A, B, C, D, E],則其子序列可以有:
刪除零個元素:[A, B, C, D, E](即自身)
刪除一個元素:[A, B, C, D]、[A, B, C, E]、[A, B, D, E]、[A, C, D, E]、[B, C, D, E]
刪除兩個元素:[A, B, C]、[A, B, D]、[A, B, E]、[A, C, D]、[A, C, E]、[A, D, E]、[B, C, D]、[B, C, E]、[B, D, E]、[C, D, E]
刪除三個元素:[A, B]、[A, C]、[A, D]、[A, E]、[B, C]、[B, D]、[B, E]、[C, D]、[C, E]、[D, E]
刪除四個元素:[A]、[B]、[C]、[D]、[E]
刪除所有元素:[](空序列)

常見問題

子序列問題在算法設計和編程競賽中非常常見。以下是幾種經典問題:
最長公共子序列(LCS):給定兩個序列,找出它們的最長公共子序列。動態規劃是解決這個問題的常用方法。
最長遞增子序列(LIS):給定一個序列,找出其中最長的遞增子序列。可以使用動態規劃或貪心算法結合二分查找解決。
子序列和問題:給定一個序列,找出所有和為特定值的子序列。可以使用回溯法或動態規劃解決。

根據我上面的介紹,可以總結,大多數子序列問題其實都可以用DP的算法來解決。

關于子序列問題的幾個例題

1.最長遞增子序列

題目鏈接
題目:

在這里插入圖片描述

樣例 輸出和輸入:

在這里插入圖片描述

首先根據上述子序列的描述,這道題就很容易理解了,就是 讓我們求給定數組的最長的遞增子序列。
算法原理:
狀態表示:dp[i]表示以i位置為結尾的所有子序列中最長的那個子序列的長度。
狀態轉移方程:
在這里插入圖片描述
首先我們要求狀態轉移方程就要看i位置的狀態,我們要確定i位置的狀態,是不是應該將0到i-1位置遍歷一遍,然后將當中的最長子序列求出來然后再加上當前位置的長度1就可以了,這是當子序列長度大于1的時候,還有一種情況是長度等于1的時候,長度等于1的時候,可以默認看做一個子序列,所以dp[i]就等于1,當長度大于1的時候,這種情況,我們先用一個變量j將0到i-1位置的最長子序列遍歷出來,然后再+1,所以狀態轉移方程:dp[i] = max(dp[j]+1,dp[i])
初始化:因為單獨一個元素就可以看做一個遞增的子序列,所以DP表中的值可以全部初始化為1.
代碼展示:

class Solution {
public:int lengthOfLIS(vector<int>& nums) {int n = nums.size();vector<int> dp(n,1);int dpmax = 1;for (int i = 1;i < n;i++){for (int j = i-1;j >= 0;j--){if (nums[j] < nums[i]){dp[i] = max(dp[j]+1,dp[i]);}dpmax=max(dp[i],dpmax);}}return dpmax;}
};

運行結果:
在這里插入圖片描述

2.擺動序列

題目鏈接
題目:

在這里插入圖片描述

樣例 輸出和輸入:

在這里插入圖片描述

這道題讓我們求擺動序列的最長的子序列的長度,首先我們要搞清楚,什么是擺動序列:
在這里插入圖片描述

上面就是一個擺動序列。
算法原理:
這道題首先要求擺動序列,我們上個專題已經做過類似的題了,就像湍流數組一樣,這道題很顯然,我們需要兩個狀態,一個狀態是向下的狀態,一個狀態是向上的狀態,這里定義f[i]是向上的狀態,g[i]是向下的狀態。
狀態表示:f[i]是以i位置為結尾的子序列中長度最長且最后一個狀態是向上的最長子序列的長度,g[i]表示以i位置為結尾最后的子序列中最后一個狀態向下的最長子序列的長度。
狀態轉移方程:首先對f[i]分析:在這里插入圖片描述
所以這里f[i]的狀態轉移方程:f[i] = max(g[j] + 1, f[i]),同理也可以求出g[i]的狀態轉移方程:g[i] = max(f[j] + 1, g[i])
代碼展示:

class Solution {
public:int wiggleMaxLength(vector<int>& nums) {int n = nums.size();vector<int> f(n,1), g(n,1);int dpmax = 1;for (int i = 1;i < n;i++){for (int j = i - 1;j >= 0;j--){if (nums[j] > nums[i]){g[i] = max(f[j] + 1, g[i]);}else if (nums[j] < nums[i]){f[i] = max(g[j] + 1, f[i]);}dpmax = max(max(dpmax, f[i]), g[i]);}}return dpmax;}
};

運行結果:
在這里插入圖片描述

3.最長遞增子序列的個數

題目鏈接
題目:

在這里插入圖片描述

樣例 輸出和輸入:

在這里插入圖片描述

這道題相對于第一道題換了一個問法。這道題是求最長子序列的個數
算法原理:
狀態表示:首先我們先定義一個狀態,看這個狀態能推下去嗎,dp[i]表示以i位置為結尾的所有子序列中,最長子序列的個數。
狀態轉移方程:首先這里就出問題了 ,這里我們根本不知道最長的子序列是什么,因為根本沒有記錄的,所以這里根本就推不出來,所以還得加一個len[i],len[i]表示以i位置為結尾的所有子序列中最長子序列的長度,將dp[i]改為count[i],count[i]表示以i位置為結尾的所有子序列中最長的子序列的個數。接下來來推狀態轉移方程,在這里插入圖片描述
有三種情況,當我們遍歷的len[j]+1==len[i],意思就是0到i-1位置的子序列中加上當前的長度和之前的最長的子序列是相同的,這里我們應該把以j位置為結尾的最長子序列的個數全部加到count[i]]中。這里畫圖表示
在這里插入圖片描述

根據這些情況可以將表填完,但是,我們還需要 一個retlen和一個retcount更新每次的最長子序列的長度和最長子序列的個數。
這里也分為三種情況,和上面的情況相同,只需要每次遍歷完一個位置,更新結果即可。

代碼展示:

class Solution {
public:int findNumberOfLIS(vector<int>& nums) {int n = nums.size();vector<int> len(n,1), count(n,1);//統計每次的每次的最終結果int retlen = 1, retcount = 1;for (int i = 1;i < n;i++){for (int j = i - 1;j >= 0;j--){//當出現遞增的時候if (nums[j] < nums[i]){//判斷如果加上遞增的那一個和當前最長的長度還是一樣的則需要更新countif (len[j] + 1 == len[i])count[i] += count[j];//如果加上當前的一個元素比比之前的最長的子序列要長,則重新規劃長度else if (len[j] + 1 > len[i])count[i] = count[j],len[i] = len[j];}}//統計每次的結果,如果len和結果的len相同,則直接用count累加if (retlen == len[i])retcount += count[i];//如果len比結果的len要大,則直接重置結果len和結果的countelse if (retlen < len[i])retcount = count[i], retlen = len[i];}return retcount;}
};

運行結果:
在這里插入圖片描述

4.最長數對鏈

題目鏈接
題目:

在這里插入圖片描述

樣例 輸出和輸入:

在這里插入圖片描述

這道題其實和求最長子序列的長度是相同的題,但是換了一個形式而已,根據題目條件我們可以得知什么是數對鏈:
在這里插入圖片描述
數對連就要滿足上述條件
算法原理:
預處理:首先我們得將數組排序,排序的規則,只需要比較每個數對的第一個元素的大小即可,因為每個數對都是單增的,如果我們排序之后保證了a>c,那么d>c是絕對大于前一個數對的,所以這里只需要根據前一個數排序即可。
狀態表示:這里dp[i]表示以i位置為結尾的所有數對鏈中最長的那個數對鏈的長度。
狀態轉移方程:分兩種情況:
在這里插入圖片描述

代碼展示:

class Solution {
public:int findLongestChain(vector<vector<int>>& pairs) {sort(pairs.begin(), pairs.end());int n = pairs.size();vector<int> dp(n, 1);int ret = 1;for (int i = 1;i < n;i++){for (int j = i - 1;j >= 0;j--){if (pairs[j][1] < pairs[i][0]){dp[i] = max(dp[j] + 1, dp[i]);}ret = max(dp[i], ret);}}return ret;}
};

運行結果:
在這里插入圖片描述

5.最長定差子序列

題目鏈接
題目:

在這里插入圖片描述

樣例 輸出和輸入:

在這里插入圖片描述

這道題給定一個difference,讓我們求出數組中的差為difference的最長的子序列的長度
算法原理:
狀態表示:dp[i]表示以i位置為結尾的所有子序列中的最長的等差子序列,且差值是difference。
狀態轉移方程:首先我們可以分析一下,我們可以選擇從0位置開始遍歷尋找和i位置之差是difference的數,這里的dp表其實我們可以借助hash表來充當,因為每次我們都得去前面找和i位置差值是difference的數,所以這里hash表既可以充當dp表,也可以將前一個位置和當前位置的差值是difference的數存起來。
這里的狀態轉移方程:hash[arr[i]] = hash[arr[i] - difference] + 1這里如果沒有在hash表中找到前一個位置差值是difference值的數,則hash[arr[i] - difference]就是0,所以也免去了這種情況,由于我們找的是離i位置最近的前一個位置,這里也可以用hash表解決,因為,我們是從左到右遍歷的,這就使得后一個位置每次都是覆蓋了前一個位置的值,每次都是最新的狀態值。

代碼展示:

class Solution {
public:int longestSubsequence(vector<int>& arr, int difference) {unordered_map<int, int> hash;//arr[i]----dp[i]hash[arr[0]] = 1;int ret = 1;for (int i = 1;i < arr.size();i++){//需要的最后一個b的值,這個hash能保證,因為從左到右遍歷,前面的值已經被覆蓋了hash[arr[i]] = hash[arr[i] - difference] + 1;ret = max(ret, hash[arr[i]]);}return ret;}
};

運行結果:

在這里插入圖片描述

總結

通過本文對子序列問題的探討,我們深入理解了動態規劃在解決此類問題中的重要性。無論是經典的最長公共子序列(LCS)問題,還是最長遞增子序列(LIS)問題,動態規劃都展示了其強大的解題能力。通過將問題分解為更小的子問題,并記錄這些子問題的解,我們能夠高效地找到最優解,避免重復計算。

此外,我們還見識了動態規劃解決子序列問題的多種變體及其實際應用。這不僅拓寬了我們對算法設計的視野,也提升了我們在面對復雜問題時的解決能力。子序列問題不僅在理論上具有重要意義,也在現實世界中的許多領域,如生物信息學、文本處理和數據分析中有著廣泛的應用。

希望通過本文的講解,讀者能對動態規劃在子序列問題中的應用有更深的理解,并能將這些技術應用于實際編程中,解決更多實際問題。動態規劃的學習不僅僅局限于特定問題,更是培養一種思維方式,一種解決復雜問題的系統方法。愿大家在未來的算法學習和應用中繼續精進,取得更大的進步。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/38351.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/38351.shtml
英文地址,請注明出處:http://en.pswp.cn/web/38351.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c語言的燙燙燙燙燙??

當初學習C語言時&#xff0c;對于一些特殊的打印輸出可能會感到困惑&#xff0c;比如會出現一堆亂碼燙燙燙的情況。其實這是因為在C語言中&#xff0c;對于字符類型和數字類型之間的隱式轉換可能會導致打印輸出的結果不符合預期。這并不意味著程序員"燙"&#xff0c;…

[激光原理與應用-96]:激光器研發與生產所要的常見設備(大全)與儀器(圖解)

目錄 一、激光器制造設備 二、測試與校準設備 2.1 光功率計&#xff1a; 1、工作原理 2、主要功能 3、應用場景 4、測量方法 5、總結 2.2. 激光束質量分析儀&#xff1a; 1、概述 2、主要功能和特點 3、工作原理 4、常見品牌和型號 5、應用領域 6、總結 2.3 光…

力扣-2529. 正整數和負整數的最大計數

文章目錄 力扣題目代碼工程 力扣題目 給你一個按 非遞減順序 排列的數組 nums &#xff0c;返回正整數數目和負整數數目中的最大值。 換句話講&#xff0c;如果 nums 中正整數的數目是 pos &#xff0c;而負整數的數目是 neg &#xff0c;返回 pos 和 neg二者中的最大值。 注…

機器人運動范圍檢測 c++

地上有一個m行n列的方格&#xff0c;一個機器人從坐標&#xff08;0&#xff0c;0&#xff09;的格子開始移動&#xff0c;它每次可以向上下左右移動一個格子&#xff0c;但不能進入行坐標和列坐標的位數之和大于k的格子&#xff0c;請問機器人能夠到達多少個格子 #include &l…

基于大數據架構的情感分析

1 項目介紹 1.1 研究目的和意義 隨著大數據時代的到來&#xff0c;電影產業積累了海量的用戶評論數據&#xff0c;這些數據中蘊含著觀眾的情感傾向與偏好信息&#xff0c;為電影推薦和市場策略制定提供了寶貴資源。然而&#xff0c;如何高效地從這浩瀚的數據海洋中提煉出有價…

QT5:在窗口右上角顯示圖標

目錄 一、環境與目標 二、實現邏輯&#xff08;純代碼&#xff09;與效果 三、參考代碼 四、總結 一、環境與目標 qt版本&#xff1a;5.12.7 windows 11 下的 Qt Designer &#xff08;已搭建&#xff09; 目標&#xff1a;使用嵌套布局的方式將兩個按鈕顯示在窗口右上角…

《大海》這歌為何經久不衰?你看歌詞寫的多美妙!

《大海》這歌為何經久不衰&#xff1f;你看歌詞寫的多美妙&#xff01; 《大海》是一首由陳大力作詞&#xff0c;陳大力、陳秀男作曲&#xff0c;Ricky Ho編曲&#xff0c;張雨生演唱的國語流行歌曲。該曲收錄在張雨生1992年11月30日由飛碟唱片發行的同名專輯《大海》中。 作為…

【JavaEE精煉寶庫】多線程進階(2)synchronized原理、JUC類——深度理解多線程編程

一、synchronized 原理 1.1 基本特點&#xff1a; 結合上面的鎖策略&#xff0c;我們就可以總結出&#xff0c;synchronized 具有以下特性(只考慮 JDK 1.8)&#xff1a; 開始時是樂觀鎖&#xff0c;如果鎖沖突頻繁&#xff0c;就轉換為悲觀鎖。 開始是輕量級鎖實現&#xff…

廣州外貿建站模板

Yamal外貿獨立站wordpress主題 綠色的亞馬爾Yamal外貿獨立站wordpress模板&#xff0c;適用于外貿公司建獨立站的wordpress主題。 https://www.jianzhanpress.com/?p7066 賽斯科Sesko-W外貿建站WP主題 適合機械設備生產廠家出海做外貿官網的wordpress主題&#xff0c;紅橙色…

Dify自定義工具例子

1.天氣&#xff08;JSON&#xff09; {"openapi": "3.1.0","info": {"title": "Get weather data","description": "Retrieves current weather data for a location.","version": "v1…

動態規劃——打家劫舍(C++)

好像&#xff0c;自己讀的書確實有點少了。 ——2024年7月2日 198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 題目描述 你是一個專業的小偷&#xff0c;計劃偷竊沿街的房屋。每間房內都藏有一定的現金&#xff0c;影響你偷竊的唯一制約因素就是相鄰的房屋裝有相互連…

Linux 靜態庫和動態庫

不管是Linux還是Windows中的庫文件其本質和工作模式都是相同的, 只不過在不同的平臺上庫對應的文件格式和文件后綴不同。程序中調用的庫有兩種 靜態庫和動態庫&#xff0c;不管是哪種庫文件本質是還是源文件&#xff0c;只不過是二進制格式只有計算機能夠識別&#xff0c;作為一…

【Node-RED 4.0.2】4.0版本新增特性(官方版)

二、重要功能 *1.時間戳格式改進 過去&#xff0c;node-red 只提供了 最原始的 timestamp 的格式&#xff08;1970-01-01 ~ now&#xff09; 但是現在&#xff0c;額外增加了 2 種格式&#xff1a; ISO 8601 -A COMMON FORMAT&#xff08;YYYY-MM-DDTHH:mm:ss:sssZ&#xff…

思考如何學習一門編程語言?

一、什么是編程語言 編程語言是一種用于編寫計算機程序的人工語言。通過編程語言&#xff0c;程序員可以向計算機發出指令&#xff0c;控制計算機執行各種任務和操作。編程語言由一組語法規則和語義規則組成&#xff0c;這些規則定義了如何編寫代碼以及代碼的含義。 編程語言…

linux和mysql基礎指令

Linux中nano和vim讀可以打開記事文件。 ifdown ens33 ifup ens33 關閉&#xff0c;開啟網絡 rm -r lesson1 gcc -o code1 code1.c 編譯c語言代碼 ./code1 執行c語言代碼 rm -r dir 刪除文件夾 mysql> show databases-> ^C mysql> show databases; -------…

常見網絡端口號

在網絡工程領域&#xff0c;了解和掌握默認端口號是至關重要的。端口號是計算機網絡中最基本的概念之 一&#xff0c;用于標識特定的網絡服務或應用程序。 1、什么是端口號&#xff1f; 端口號是計算機網絡中的一種標識&#xff0c;用于區分不同的網絡服務和應用程序。每個端…

【C++進階學習】第五彈——二叉搜索樹——二叉樹進階及set和map的鋪墊

二叉樹1&#xff1a;深入理解數據結構第一彈——二叉樹&#xff08;1&#xff09;——堆-CSDN博客 二叉樹2&#xff1a;深入理解數據結構第三彈——二叉樹&#xff08;3&#xff09;——二叉樹的基本結構與操作-CSDN博客 二叉樹3&#xff1a;深入理解數據結構第三彈——二叉樹…

想要打造超高性能的接口API?試試這12條小技巧。

1. 并行處理 簡要說明 舉個例子&#xff1a;在價格查詢鏈路中&#xff0c;我們需要獲取多種獨立的價格配置項信息&#xff0c;如基礎價、折扣價、商戶活動價、平臺活動價等等。 CompletableFuture 是銀彈嗎&#xff1f; 使用 CompletableFuture 的確能夠幫助我們解決許多獨…

走進IT的世界

引言 隨著高考的結束&#xff0c;對于即將踏入IT&#xff08;信息技術&#xff09;領域的新生而言&#xff0c;這個假期不僅是放松身心的時間&#xff0c;更是提前規劃、深化專業知識、為大學生活奠定堅實基礎的寶貴機會。以下是一份詳盡的高考假期預習與規劃指南&#xff0c;…

Android自動化測試實踐:uiautomator2 核心功能與應用指南

Android自動化測試實踐&#xff1a;uiautomator2 核心功能與應用指南 uiautomator2 是一個用于Android應用的自動化測試Python庫&#xff0c;支持多設備并行測試操作。它提供了豐富的API來模擬用戶對App的各種操作&#xff0c;如安裝、卸載、啟動、停止以及清除應用數據等。此外…