1. 程式人生 > 其它 >583.兩個字串的刪除操作

583.兩個字串的刪除操作

目錄

583.兩個字串的刪除操作

題目

給定兩個單詞word1和word2,找到使得word1和word2相同所需的最小步數,每步可以刪除任意一個字串中的一個字元。

示例:

輸入: "sea", "eat"
輸出: 2
解釋: 第一步將"sea"變為"ea",第二步將"eat"變為"ea"

提示:

給定單詞的長度不超過500。
給定單詞中的字元只含有小寫字母。

來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/delete-operation-for-two-strings
著作權歸領釦網路所有。商業轉載請聯絡官方授權,非商業轉載請註明出處。

題解

一般刪除操作很少做,因為刪除之後字元的位置改變了,是很麻煩的。所以這道題應該可以做轉換。

刪除之後相對位置是沒有變的,找到word1和word2相同。這個不就是之前的最長公共子序列嗎?

那麼這道題可以轉化為求最長公共子序列的長度,刪除的=總的-最長公共子序列的長度*2

定義dp陣列及其下邊的含義

dp[i][j]表示以[i-1]結尾的字串1與以[j-1]結尾的字串2之間的最長公共子序列的長度為dp[i][j]

dp陣列遞推式

如果word1[i-1] == word2[j-1],說明當前兩個字元可以接上之前的最長公共子序列構成新的最長公共子序列,那麼長度肯定是之前的+1,dp[i][j] = dp[i-1][j-1] + 1

如果word1[i-1] ≠ word2[j-1],有兩種路徑可以達到,i從i-2往前走一步,或者j從j-2往前走一步,為什麼不兩個同時走一步?因為雖然word1[i-1] ≠ word2[j-1],但是可能word1[i-1] == word2[j-2],如果兩個同時不看就會漏掉這種情況。
dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1])

dp陣列初始化
i=0和j=0時在本題時沒有意義的,初始化為0即可,這裡採用類的成員函式預設初始化值不顯示初始化

遍歷順序

int len1=word1.length();
int len2=word2.length();
if(len1==0) return len2;
if(len2==0) return len1;
int dp [] [] = new int [len1+1][len2+1];
for(int i=1;i<=len1;i++){
	for(int j=1;j<=len2;j++){
		if(word1.charAt(i-1)==word2.charAt(j-1))
			dp[i][j] = dp[i-1][j-1] + 1;
		else dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
	}
}
return len1+len2-dp[len1][len2];

空間優化
還是老思路

dp[i][j]只與dp[i-1][j-1]、dp[i-1]、dp[i][j-1]有關。

如果我們壓縮成一維陣列,
dp([i])[j] = dp([i-1])[j-1] + 1
執行dp([i])[j] = Math.max(dp([i-1])[j],dp([i])[j-1])時,發現dp([i])[j-1]和上面dp([i-1])[j-1]表示都是dp[j-1],那這裡取得是相同值,肯定是不行的,按執行的順序i會比i-1後執行,那麼此處dp[j-1]儲存的是dp([i])[j-1]的值,所以我們需要在i-1的時候儲存dp[i-1][j-1]的值

int len1=word1.length();
int len2=word2.length();
if(len1==0) return len2;
if(len2==0) return len1;
int dp [] = new int[len2+1];
int tmp = 0;
int last;
for(int i=1;i<len1;i++){
	last = dp[0];//每次迴圈需要歸位,不然使用的就是結尾的左對角線
	for(int j=1;j<len2;j++){
		tmp = dp[j]; //儲存的是dp[i-1][j]
		if(word1.charAt(i-1)==word2.charAt(j-1))
			//dp[i][j] = dp[i-1][j-1] + 1;
			//dp[j] = dp[j-1] + 1;
			dp[j] = last + 1;
		//else dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);
		else dp[j] = Math.max(dp[j],dp[j-1]);
		 last = tmp;  //對下一次迴圈(下一次j本次是j-1)的last來說dp[i-1][j-1]
	}
}