判断子序列不同的子序列两个字符串的删除操作编辑距离
引言
下面的四種題相互間都有聯(lián)系,都是類似編輯距離類的題目,這里從簡單開始,逐漸深入;
判斷子序列
給定字符串 s 和 t ,判斷 s 是否為 t 的子序列。
字符串的一個子序列是原始字符串刪除一些(也可以不刪除)字符而不改變剩余字符相對位置形成的新字符串。(例如,"ace"是"abcde"的一個子序列,而"aec"不是)。
示例 1:
輸入:s = “abc”, t = “ahbgdc”
輸出:true
示例 2:
輸入:s = “axc”, t = “ahbgdc”
輸出:false
提示:
0 <= s.length <= 100
0 <= t.length <= 10^4
兩個字符串都只由小寫字符組成。
這道題我們其實只需要計算刪除的情況就可以;(其實可以想象為把 t 的每一個和 s 不相等的字符刪除直到和 s 一樣)
1,dp[i][j]表示以下標i-1為結(jié)尾的字符串s,和以下標j-1為結(jié)尾的字符串t,相同子序列的長度;
2,這里就有兩種情況:
s[i - 1] == t[j - 1] 此時就說明 s 中的一個字符在 t 中存在;即dp[i][j] = dp[i - 1][j - 1] + 1;
s[i - 1] != t[j - 1] 這時就需要刪除 t 的這個字符,繼續(xù)和 s 匹配;即dp[i][j] = dp[i][j - 1]
3,初始化時發(fā)現(xiàn)dp[i][0]和dp[0][j]是沒有意義的,但是為了轉(zhuǎn)移方程的計算,還是需要初始化為0;
4,由轉(zhuǎn)移方程可知道遍歷順序是從前到后,從上到下;
代碼如下:
這道題只涉及了一個類似刪除操作,因為t中字符與s一個不同就刪一個,直到留下最后相同的;下面再看一道:
不同的子序列
給定一個字符串 s 和一個字符串 t ,計算在 s 的子序列中 t 出現(xiàn)的個數(shù)。
字符串的一個 子序列 是指,通過刪除一些(也可以不刪除)字符且不干擾剩余字符相對位置所組成的新字符串。(例如,“ACE” 是 “ABCDE” 的一個子序列,而 “AEC” 不是)
題目數(shù)據(jù)保證答案符合 32 位帶符號整數(shù)范圍。
提示:
0 <= s.length, t.length <= 1000
s 和 t 由英文字母組成
這道題相對上一道就稍微復(fù)雜一些,但是依然可以看出只涉及了刪除操作;
1,dp[i][j]表示以 i-1 為結(jié)尾的 s 子序列中出現(xiàn)的以 j-1 為結(jié)尾的 t 的個數(shù)為dp[i][j];
2,同樣分為兩種情況:
當s[i - 1] 與 t[j - 1]相等時,有兩部分
一部分是用s[i - 1]來匹配,那么個數(shù)為dp[i - 1][j - 1];
另一部分是不用s[i - 1]匹配,個數(shù)為dp[i - 1][j];
為什么不用s[i - 1]匹配呢?比如s為raa,t為ra,我可以用s[i - 1]匹配,則是s[0],s[2],我如果不用s[i - 1]匹配,則是s[0],s[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]來匹配,即:dp[i - 1][j],
其實這里 i - 1 就可以理解為一個刪除操作,將因為不匹配,所以減小匹配范圍
3,初始化這里需要注意,
dp[i][0]表示以i-1為結(jié)尾的s可以隨便刪除元素,出現(xiàn)空字符串的個數(shù)。
則dp[i][0]一定都是1,因為也就是把以i-1為結(jié)尾的s,刪除所有元素,出現(xiàn)空字符串的個數(shù)就是1。
dp[0][j]則是s為空,那么怎么都無法匹配到t,所以都為0;
dp[0][0] 則代表空字符串s,刪除0個元素變成t,所以為1;
4,遍歷順序很容易就看出來從前到后,從上到下;
代碼如下:
class Solution { public:int numDistinct(string s, string t) {int len1 = s.size(), len2 = t.size();vector<vector<unsigned long long>> dp(len1 + 1, vector<unsigned long long>(len2 + 1));//防止超限for (int i = 0; i <= len1; ++i) dp[i][0] = 1;//i為0是因為要把dp[0][0]初始化為0for (int i = 1; i <= len2; ++i) dp[0][i] = 0;for (int i = 1; i <= len1; ++i) {for (int j = 1; j <= len2; ++j) {if (s[i - 1] == t[j - 1])dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];elsedp[i][j] = dp[i - 1][j];}}return dp[len1][len2];} };這道題也就有點難度了,但是總歸還是只有一個刪除操作,看下面這道題
兩個字符串的刪除操作
給定兩個單詞 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步數(shù),每步可以刪除任意一個字符串中的一個字符。
示例:
輸入: “sea”, “eat”
輸出: 2
解釋: 第一步將"sea"變?yōu)?#34;ea",第二步將"eat"變?yōu)?#34;ea"
提示:
給定單詞的長度不超過500。
給定單詞中的字符只含有小寫字母。
這道題目就需要刪除兩個字符串了,但是方法還是一樣的;
1,dp[i][j]表示以i-1為結(jié)尾的字符串word1,和以j-1位結(jié)尾的字符串word2,想要達到相等,所需要刪除元素的最少次數(shù)。
2,這里的轉(zhuǎn)移方程依舊分為兩種情況:
當word1[i - 1] 與 word2[j - 1]相同的時候,dp[i][j] = dp[i - 1][j - 1];
當word1[i - 1] 與 word2[j - 1]不相同的時候,有三種情況:
一:刪word1[i - 1],最少操作次數(shù)為dp[i - 1][j] + 1
二:刪word2[j - 1],最少操作次數(shù)為dp[i][j - 1] + 1
三:同時刪word1[i - 1]和word2[j - 1],操作的最少次數(shù)為dp[i - 1][j - 1] + 2
最后取三者最小值即可,dp[i][j] = min(min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + 2);
3,初始化需要注意
當word2為空串,那么dp[i][0]就是以i-1為結(jié)尾的字符串word1要刪除多i個元素,才能和word2相同,即dp[i][0] = i。
當word1為空串,那么dp[0][j]就是以j-1為結(jié)尾的字符串word2要刪除j個元素,才能和word1相同,即dp[i][0] = i。
4,遍歷順序很容易看出來,從上到下,從左到右;
代碼如下:
class Solution { public:int minDistance(string word1, string word2) {int len1 = word1.size(), len2 = word2.size();vector<vector<int>> dp(len1 + 1, vector<int>(len2 + 1));for (int i = 0; i <= len1; ++i) dp[i][0] = i;for (int i = 0; i <= len2; ++i) dp[0][i] = i;for (int i = 1; i <= len1; ++i) {for (int j = 1; j <= len2; ++j) {if (word1[i - 1] == word2[j - 1])dp[i][j] = dp[i - 1][j - 1];elsedp[i][j] = min(min(dp[i - 1][j] + 1, dp[i][j - 1] + 1), dp[i - 1][j - 1] + 2);}}return dp[len1][len2];} };最后的大boss終于要來了,但是通過前三道題,應(yīng)該對這種題目有點感覺了吧;
編輯距離
給你兩個單詞 word1 和 word2,請你計算出將 word1 轉(zhuǎn)換成 word2 所使用的最少操作數(shù) 。
你可以對一個單詞進行如下三種操作:
插入一個字符
刪除一個字符
替換一個字符
示例 1:
輸入:word1 = “horse”, word2 = “ros”
輸出:3
解釋:
horse -> rorse (將 ‘h’ 替換為 ‘r’)
rorse -> rose (刪除 ‘r’)
rose -> ros (刪除 ‘e’)
示例 2:
輸入:word1 = “intention”, word2 = “execution”
輸出:5
解釋:
intention -> inention (刪除 ‘t’)
inention -> enention (將 ‘i’ 替換為 ‘e’)
enention -> exention (將 ‘n’ 替換為 ‘x’)
exention -> exection (將 ‘n’ 替換為 ‘c’)
exection -> execution (插入 ‘u’)
提示:
0 <= word1.length, word2.length <= 500
word1 和 word2 由小寫英文字母組成
這道題就有了三步操作,但是不管怎么樣,和之前的幾道題都是一模一樣的;
1,dp[i][j] 表示以下標i-1為結(jié)尾的字符串word1,和以下標j-1為結(jié)尾的字符串word2,最近編輯距離為dp[i][j];
2,這里還是兩種情況
如果word1[i - 1] == word2[j - 1]時,不需要任何操作,直接讓dp[i][j] = dp[i - 1][j - 1];
如果word1[i - 1] != word2[j - 1],這時候分為三部,對應(yīng)的就是三種操作
一:word1增加一個元素,使word1[i - 1]與word2[j - 1]相同,即 dp[i][j] = dp[i - 1][j] + 1
二:word1減去一個元素,即word2增添一個元素,使word1[i - 1]與word2[j - 1]相同,即 dp[i][j] = dp[i][j - 1] + 1;
三:替換操作,word1替換word1[i - 1],使其與word2[j - 1]相同,即 dp[i][j] = dp[i - 1][j - 1] + 1;
3,初始化dp[i][0] :以下標i-1為結(jié)尾的字符串word1,和空字符串word2,則只需要對word1做減去操作即可
dp[i][0] = i;
dp[0][j] = j同理;
4,循環(huán)順序老套路;
代碼如下:
總結(jié)
這幾道題還是多看看,理解一下,看不下去歇會看,看久了容易暈;
《新程序員》:云原生和全面數(shù)字化實踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
以上是生活随笔為你收集整理的判断子序列不同的子序列两个字符串的删除操作编辑距离的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 最长重复子数组最长公共子序列不相交的线
- 下一篇: set/multiset/unorder