思路:刪除兩個字串的字元使它們相等:
input:
"sea"
,"eat"
output:
2explanation: you need one step to make "sea" to "ea" and another step to make "eat" to "ea"
.
———————————更新———————————
這一題,我又一次沒有想到最長公共子串行的方法,採用了最土的遞迴法?而且還超時!
int min = integer.max_value;
public
intmindistance
(string word1, string word2)
public
void
helper
(string word1,string word2,
int start1,
int start2,
int num)
if(start1 == word1.
length()
|| start2 == word2.
length()
)if(word1.
charat
(start1)
== word2.
charat
(start2)
)else
}
當我準備使用記憶化遞迴時發現我的遞迴函式並沒有返回值。。。所以無法為visited陣列賦值,因此我還是轉戰動態規劃了。。。
public
intmindistance
(string word1, string word2)
else}}
return dp[word1.
length()
][word2.
length()
];}
然後就順利一次通過,再次記錄一下我的錯誤思路!
———————分割線(這裡是年前寫的)———————
這一題顯然可以使用動態規劃,這裡提供兩種動態規劃的思路。我們用dp[i][j]表示的word1的前i個字元與word2的前j個字元達到相同所需的最小步數,更新規則如下:
(1)如果word1.charat(i-1) == word2.charat(j-1),那麼不需要刪除任何字元,dp[i][j]的值和dp[i - 1][j - 1]的值相同:dp[i][j] = dp[i - 1][j - 1];
(2)如果word1[i - 1] == word2[j - 1]不成立則需要考慮是刪除word1.charat(i-1)還是 word2.charat(j-1),取其中最小的即可,但是無論word1.charat(i-1) == word2.charat(j-1)是否成立,都有:
dp[i][j] = math.min(dp[i][j],math.min(dp[i-1][j]+1,dp[i][j-1]+1));
然後按照更新規則更新即可:
for
(int i=
1;i<=word1.
length()
;i++
) dp[i]
[j]= math.
min(dp[i]
[j],math.
min(dp[i-1]
[j]+
1,dp[i]
[j-1]+
1));
}}
但是這裡需要注意的是,我們一定要對dp陣列初始化,將最開始的所有值設定為最大值,如果不初始化則在遍歷陣列是min之後最小值永遠是0,例如dp[i][0]和dp[0][j]也需要賦初始值(相當於乙個空串和乙個字串比較,當然返回值就是那個字串的長度了,也就是全部刪去即可):
for
(int i=
0;i<=word1.
length()
;i++
) arrays.
fill
(dp[i]
,integer.max_value)
;for
(int i=
0;i<=word1.
length()
;i++
) dp[i][0
]= i;
for(
int j=
0;j<=word2.
length()
;j++
) dp[0]
[j]= j;
完整**如下:
public
intmindistance
(string word1, string word2)
dp[i]
[j]= math.
min(dp[i]
[j],math.
min(dp[i-1]
[j]+
1,dp[i]
[j-1]+
1));
}}return dp[word1.
length()
][word2.
length()
];}
當然還有另乙個比較巧妙地思路,將該題轉換為求兩個字串的最長公共子串行問題,那最後結果就是刪去除最長公共子串行的長度即可(之前寫過最長公共子串行的題解,不懂的可以戳這裡ο(=•ω<=)ρ⌒☆):
public
intmindistance
(string word1, string word2)
else}}
return m + n -
2* dp[m]
[n];
}
另外,dfs也可以用來解這一題,也是先求最長公共子串行然後返回s1.length() + s2.length() - 2 * lcs(s1, s2, s1.length(), s2.length())即可:
public
intmindistance
(string s1, string s2)
public
intlcs
(string s1, string s2,
int m,
int n)
當然也可以從字串首部開始遍歷:
public
intmindistance
(string s1, string s2)
public
intlcs
(string s1, string s2,
int m,
int n)
但是不幸的是,這兩個dfs方法都超時了,接下來對dfs方法進行優化,我們採用記憶化回溯。我們知道在dfs過程中會不斷的回溯,同的 i 和 j 值在不同的函式呼叫路徑中會重複求解,儘管可能在前某次回溯中已經求解過該值了。只要相同的 i 和 j 對應的函式被呼叫一次,我們可以使用 memo 陣列儲存相應函式的返回值來避免後續訪問的冗餘。memo[i][j] 被用來儲存函式呼叫 lcs(s1, s2, i, j)的返回值。實際上這就是變相的動態規劃,而memo[i][j]相當於dp陣列:
public
intmindistance
(string s1, string s2)
public
intlcs
(string s1, string s2,
int m,
int n,
int[
] memo)
這樣就不會超出時間限制了,這證明通過返回已經在 memo 陣列中儲存的值,我們可以給搜尋過程極大程度的剪枝。 583 兩個字串的刪除操作
給定兩個單詞 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步數,每步可以刪除任意乙個字串中的乙個字元。示例 1 說明 1.給定單詞的長度不超過500。2.給定單詞中的字元只含有小寫字母。為了求得最少刪除次數,我們可以求出串 s1和串 s2最長公共子串行,我們記為 ...
583 兩個字串的刪除操作
題目描述 給定兩個單詞 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步數,每步可以刪除任意乙個字串中的乙個字元。解題思路 動態規劃,和最長公共子串行相似,根據當前結尾的兩個字元是否相等選擇不同的轉移方式,如下 class solution def mindista...
583 兩個字串的刪除操作
題目描述 給定兩個單詞 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步數,每步可以刪除任意乙個字串中的乙個字元。示例 輸入 sea eat 輸出 2 解釋 第一步將 sea 變為 ea 第二步將 eat 變為 ea 給定單詞的長度不超過500。給定單詞中的字元只含...