代碼隨想錄算法訓練營第58天|動態規劃part15|392.判斷子序列、115.不同的子序列

代碼隨想錄算法訓練營第58天|動態規劃part15|392.判斷子序列、115.不同的子序列

392.判斷子序列

392.判斷子序列

思路:

(這道題也可以用雙指針的思路來實現,時間復雜度也是O(n))

這道題應該算是編輯距離的入門題目,因為從題意中我們也可以發現,只需要計算刪除的情況,不用考慮增加和替換的情況。

所以掌握本題的動態規劃解法是對后面要講解的編輯距離的題目打下基礎。

動態規劃五部曲分析如下:

  1. 確定dp數組(dp table)以及下標的含義

dp[i][j] 表示以下標i-1為結尾的字符串s,和以下標j-1為結尾的字符串t,相同子序列的長度為dp[i][j]。

注意這里是判斷s是否為t的子序列。即t的長度是大于等于s的。

  1. 確定遞推公式

在確定遞推公式的時候,首先要考慮如下兩種操作,整理如下:

  • if (s[i - 1] == t[j - 1])
    t中找到了一個字符在s中也出現了
  • if (s[i - 1] != t[j - 1])
    相當于t要刪除元素,繼續匹配

if (s[i - 1] == t[j - 1]),那么dp[i][j] = dp[i - 1][j - 1] + 1;,因為找到了一個相同的字符,相同子序列長度自然要在dp[i-1][j-1]的基礎上加1(如果不理解,在回看一下dp[i][j]的定義)

if (s[i - 1] != t[j - 1]),此時相當于t要刪除元素,t如果把當前元素t[j - 1]刪除,那么dp[i][j] 的數值就是 看s[i - 1]與 t[j - 2]的比較結果了,即:dp[i][j] = dp[i][j - 1];

  1. dp數組如何初始化

從遞推公式可以看出dp[i][j]都是依賴于dp[i - 1][j - 1] 和 dp[i][j - 1],所以dp[0][0]和dp[i][0]是一定要初始化的。

這里大家已經可以發現,在定義dp[i][j]含義的時候為什么要表示以下標i-1為結尾的字符串s,和以下標j-1為結尾的字符串t,相同子序列的長度為dp[i][j]。

因為這樣的定義在dp二維矩陣中可以留出初始化的區間,如圖:

如果要是定義的dp[i][j]是以下標i為結尾的字符串s和以下標j為結尾的字符串t,初始化就比較麻煩了。

dp[i][0] 表示以下標i-1為結尾的字符串,與空字符串的相同子序列長度,所以為0. dp[0][j]同理。

vector<vector<int>> dp(s.size() + 1, vector<int>(t.size() + 1, 0));

  1. 確定遍歷順序

同理從遞推公式可以看出dp[i][j]都是依賴于dp[i - 1][j - 1] 和 dp[i][j - 1],那么遍歷順序也應該是從上到下,從左到右

在這里插入圖片描述

  1. 舉例推導dp數組

在這里插入圖片描述

dp[i][j]表示以下標i-1為結尾的字符串s和以下標j-1為結尾的字符串t 相同子序列的長度,所以如果dp[s.size()][t.size()] 與 字符串s的長度相同說明:s與t的最長相同子序列就是s,那么s 就是 t 的子序列。

圖中dp[s.size()][t.size()] = 3, 而s.size() 也為3。所以s是t 的子序列,返回true。

代碼:

python

class Solution(object):def isSubsequence(self, s, t):""":type s: str:type t: str:rtype: bool"""dp = [[0] * (len(t)+1) for _ in range(len(s)+1)]for i in range(1, len(s)+1):for j in range(1, len(t)+1):if s[i-1] == t[j-1]:dp[i][j] = dp[i-1][j-1] + 1else:dp[i][j] = dp[i][j-1]return dp[-1][-1] == len(s)

115.不同的子序列

115.不同的子序列

思路:

動態規劃五部曲:

  1. 確定dp數組(dp table)以及下標的含義

dp[i][j]:以i-1為結尾的s子序列中出現以j-1為結尾的t的個數為dp[i][j]。

  1. 確定遞推公式

這一類問題,基本是要分析兩種情況

  • s[i - 1] 與 t[j - 1]相等
  • s[i - 1] 與 t[j - 1] 不相等

當s[i - 1] 與 t[j - 1]相等時,dp[i][j]可以有兩部分組成。

一部分是用s[i - 1]來匹配,那么個數為dp[i - 1][j - 1]。即不需要考慮當前s子串和t子串的最后一位字母,所以只需要 dp[i-1][j-1]。

一部分是不用s[i - 1]來匹配,個數為dp[i - 1][j]。

這里可能有錄友不明白了,為什么還要考慮 不用s[i - 1]來匹配,都相同了指定要匹配啊。

所以當s[i - 1] 與 t[j - 1]相等時,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];

當s[i - 1] 與 t[j - 1]不相等時,dp[i][j]只有一部分組成,不用s[i - 1]來匹配(就是模擬在s中刪除這個元素),即:dp[i - 1][j]

所以遞推公式為:dp[i][j] = dp[i - 1][j];

  1. dp數組如何初始化

從遞推公式dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; 和 dp[i][j] = dp[i - 1][j]; 中可以看出dp[i][j] 是從上方和左上方推導而來,如圖:,那么 dp[i][0] 和dp[0][j]是一定要初始化的。

在這里插入圖片描述

每次當初始化的時候,都要回顧一下dp[i][j]的定義,不要憑感覺初始化。

dp[i][0]表示什么呢?

dp[i][0] 表示:以i-1為結尾的s可以隨便刪除元素,出現空字符串的個數。

那么dp[i][0]一定都是1,因為也就是把以i-1為結尾的s,刪除所有元素,出現空字符串的個數就是1。

再來看dp[0][j],dp[0][j]:空字符串s可以隨便刪除元素,出現以j-1為結尾的字符串t的個數。

那么dp[0][j]一定都是0,s如論如何也變成不了t。

最后就要看一個特殊位置了,即:dp[0][0] 應該是多少。

dp[0][0]應該是1,空字符串s,可以刪除0個元素,變成空字符串t。

vector<vector<long long>> dp(s.size() + 1, vector<long long>(t.size() + 1));
for (int i = 0; i <= s.size(); i++) dp[i][0] = 1;
for (int j = 1; j <= t.size(); j++) dp[0][j] = 0; // 其實這行代碼可以和dp數組初始化的時候放在一起,但我為了凸顯初始化的邏輯,所以還是加上了。
  1. 確定遍歷順序

從遞推公式dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; 和 dp[i][j] = dp[i - 1][j]; 中可以看出dp[i][j]都是根據左上方和正上方推出來的。

在這里插入圖片描述

所以遍歷的時候一定是從上到下,從左到右,這樣保證dp[i][j]可以根據之前計算出來的數值進行計算。

for (int i = 1; i <= s.size(); i++) {for (int j = 1; j <= t.size(); j++) {if (s[i - 1] == t[j - 1]) {dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];} else {dp[i][j] = dp[i - 1][j];}}
}
  1. 舉例推導dp數組

以s:“baegg”,t:"bag"為例,推導dp數組狀態如下:

在這里插入圖片描述

代碼:

python

class Solution:def numDistinct(self, s: str, t: str) -> int:dp = [[0] * (len(t)+1) for _ in range(len(s)+1)]for i in range(len(s)):dp[i][0] = 1for j in range(1, len(t)):dp[0][j] = 0for i in range(1, len(s)+1):for j in range(1, len(t)+1):if s[i-1] == t[j-1]:dp[i][j] = dp[i-1][j-1] + dp[i-1][j]else:dp[i][j] = dp[i-1][j]return dp[-1][-1]

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

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

相關文章

[Android 11]使用Android Studio調試系統應用之Settings移植(七):演示用AS編譯錯誤問題

文章目錄 1. 篇頭語2. 系列文章3. AS IDE的配置3.1 AS版本3.2 Gradle JDK 版本4. JDK的下載5. AS演示工程地址6.其他版本JDK導致的錯誤1. 篇頭語 距離2021年開始,系列文章發表已經有近兩年了,依舊有網友反饋一些gitee上演示源碼編譯的一些問題,這里就記錄一下。 2. 系列文章…

uniApp引入vant2

uniApp引入vant2 1、cnpm 下載&#xff1a;cnpm i vantlatest-v2 -S2、main.js文件引入 import Vant from ./node_modules/vant/lib/vant;Vue.use(Vant);3.app.vue中引入vant 樣式文件 import /node_modules/vant/lib/index.css;

tomcat服務七層搭建動態頁面查看

一個服務器多實例復制完成 配置tomcat多實例的環境變量 vim /etc/profile.d/tomcat.sh配置tomcat1和tomcat2的環境變量 進入tomcat1修改配置 測試通信端口是否正常 連接正常 toncat 2 配置修改 修改這三個 端口配置修改完成 修改tomcat1 shudown 分別把啟動文件指向tomcat1…

數據結構--最短路徑 Dijkstra算法

數據結構–最短路徑 Dijkstra算法 Dijkstra算法 計算 b e g i n 點到各個點的最短路 \color{red}計算\ begin\ 點到各個點的最短路 計算 begin 點到各個點的最短路 如果是無向圖&#xff0c;可以先把無向圖轉化成有向圖 我們需要2個數組 final[] &#xff08;標記各頂點是否已…

【ARM 嵌入式 編譯系列 10.1 -- GCC 編譯縮減可執行文件 elf 文件大小】

文章目錄 上篇文章&#xff1a;ARM 嵌入式 編譯系列 10 – GCC 編譯縮減可執行文件 elf 文件大小 接著上篇文章 ARM 嵌入式 編譯系列 10 – GCC 編譯縮減可執行文件 elf 文件大小 的介紹&#xff0c;我們看下如何進一步縮小可執行文件test的大小。上篇文章通過 strip --strip-…

RunnerGo的相比較JMeter優勢,能不能替代?

目前在性能測試領域市場jmeter占有率是非常高的&#xff0c;主要原因是相對比其他性能測試工具使用更簡單&#xff08;開源、易擴展&#xff09;&#xff0c;功能更強大&#xff08;滿足多種協議的接口&#xff09;&#xff0c;但是隨著研發協同的升級&#xff0c;平臺化的性能…

進程的概念和特征

進程的概念和特征 進程的概念進程的特征 進程的概念 在多道程序環境下&#xff0c;允許多個程序并發執行&#xff0c;此時他們將失去封閉性&#xff0c;并具有間斷性及不可再現性的特征。為此引入了進程&#xff08;process&#xff09;的概念&#xff0c;以便更好的描述和控制…

【Java】常用工具——異常

1. try-catch-finnaly try必須和catch或者finally組合使用&#xff1b; public class TryDemoOne {public static void main(String[] args) {Scanner input new Scanner(System.in);System.out.println("輸入第1個整數&#xff1a;");int one input.nextInt();S…

主流的嵌入式微處理器

目前主流的嵌入式微處理器系列有&#xff1a; ARM系列 MIPS系列 PowerPC系列 Super H系列 一、MPC/PPC系列 PowerPC(簡稱PPC),其基本設計源自IBM的POWER.1991年&#xff0c;APPLE(蘋果電腦)、IBM、Motorola&#xff08;摩托羅拉&#xff09;組成的AIM聯盟發展出Power微處理器…

mybatis-plus 根據指定字段 批量 刪除/修改

mybatis-plus 提供了根據id批量更新和修改的方法,這個大家都不陌生 但是當表沒有id的時候怎么辦 方案一: 手寫SQL方案二: 手動獲取SqlSessionTemplate 就是把mybatis plus 干的事自己干了方案三 : 重寫 executeBatch 方法結論: mybatis-plus 提供了根據id批量更新和修改的方法,…

Python jupyter lab 設置

在下載好jupyter lab 后&#xff0c;需要對其進行設置&#xff0c;尤其是遠程服務器的時候&#xff0c;因為根本就是沒有屏幕&#xff0c;也沒有瀏覽器。 新建設置文件 jupyter lab --generate-config設置文件內部參數 vim ~/.jupyter/jupyter_lab_config.py進去一通改&#…

網絡編程(8.15)io模型,IO多路復用(select,poll)

1.使用select函數實現IO多路復用 使用select函數實現IO多路復用的服務器&#xff1a; #include<stdio.h> #include<head.h> #include<netinet/in.h> #include<sys/select.h> #include<arpa/inet.h> #define PROT 1112 #define IP "192.16…

29 | 廣州美食店鋪數據分析

廣州美食店鋪數據分析 一、數據分析項目MVP加/價值主張宣言 隨著經濟的快速發展以及新媒體的興起,美食攻略、美食探店等一系列東西進入大眾的眼球,而人們也會在各大平臺中查找美食推薦,因此本項目做的美食店鋪數據分析也是帶有可行性的。首先通過對廣東省的各市美食店鋪數量…

對話即數據分析,網易數帆ChatBI做到了

大數據產業創新服務媒體 ——聚焦數據 改變商業 在當今數字化快速發展的時代&#xff0c;數據已經成為業務經營與管理決策的核心驅要素。無論是跨國大企業還是新興創業公司&#xff0c;正確、迅速地洞察數據已經變得至關重要。然而&#xff0c;傳統的BI工具往往對用戶有一定的…

初步認識OSI/TCP/IP一(第三十八課)

1 初始OSI模型 OSI參考模型(Open Systems Interconnection Reference Model)是一個由國際標準化組織(ISO)和國際電報電話咨詢委員會(CCITT)聯合制定的網絡通信協議規范,它將網絡通信分為七個不同的層次,每個層次負責不同的功能和任務。 2 網絡功能 數據通信、資源共享…

MTK Android非常用分辨率修改充電動畫

非標準分辨率的屏,配置MTK Android的關機充電動畫. 環境 芯片 MTK 系統 Android 服務器 ubuntu 屏幕分辨率356*400,不是常見的分辨率. 原始充電動畫顯示異常,畫面扭曲. 方法 確定使用的圖片 vendor/mediatek/proprietary/bootable/bootloader/lk/dev/logo 這個目錄下…

springboot多模塊打包方式

明確子父模塊結構 父目錄是帶modules 大致結構如下&#xff1a; <modules><module>ruoyi-admin</module><module>ruoyi-framework</module><module>ruoyi-system</module><module>ruoyi-quartz</module><module>…

htmlCSS-----高級選擇器

目錄 前言 偽類選擇器 狀態類 結構類 偽元素選擇器 屬性選擇器 前言 前面我們學習了CSS中的相關選擇器&#xff08;鏈接html&CSS-----CSS選擇器&#xff08;上&#xff09;_灰勒塔德的博客-CSDN博客 html&CSS-----CSS選擇器&#xff08;下&#xff09;_灰勒塔…

計算機視覺中的Transformer

幾十年來&#xff0c;理論物理學家一直在努力提出一個宏大的統一理論。通過統一&#xff0c;指的是將被認為是完全不同的兩個或多個想法結合起來&#xff0c;將它們的不同方面證明為同一基礎現象。一個例子是在19世紀之前&#xff0c;電和磁被看作是無關的現象&#xff0c;但電…

基于java的汽車改裝方案網站設計與實現

摘要 本文主要講述了基于SpringBootMySql開發技術開發的汽車改裝方案網站的設計與實現。這里的汽車改裝方案網站是通過一個平臺使所有的汽車愛好者們可以不用出門就可以體驗到專業的汽車改裝方案設計服務。現實生活中如果需要進行汽車改裝的方案設計&#xff0c;往往要跑很多次…