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