[LeetCode] Minimum ASCII Delete Sum for Two Strings 兩個字符串的最小ASCII刪除和

 

Given two strings s1, s2, find the lowest ASCII sum of deleted characters to make two strings equal.html

Example 1:python

Input: s1 = "sea", s2 = "eat"
Output: 231
Explanation: Deleting "s" from "sea" adds the ASCII value of "s" (115) to the sum.
Deleting "t" from "eat" adds 116 to the sum.
At the end, both strings are equal, and 115 + 116 = 231 is the minimum sum possible to achieve this.

 

Example 2:面試

Input: s1 = "delete", s2 = "leet"
Output: 403
Explanation: Deleting "dee" from "delete" to turn the string into "let",
adds 100[d]+101[e]+101[e] to the sum.  Deleting "e" from "leet" adds 101[e] to the sum.
At the end, both strings are equal to "let", and the answer is 100+101+101+101 = 403.
If instead we turned both strings into "lee" or "eet", we would get answers of 433 or 417, which are higher.

 

Note:數組

  • 0 < s1.length, s2.length <= 1000.
  • All elements of each string will have an ASCII value in [97, 122].

 

這道題給了咱們兩個字符串,讓咱們刪除一些字符使得兩個字符串相等,咱們但願刪除的字符的ASCII碼最小。這道題跟以前那道Delete Operation for Two Strings極其相似,那道題讓求刪除的最少的字符數,這道題換成了ASCII碼值。其實不少大廠的面試就是這種改動,雖然不多出原題,可是這種小範圍的改動倒是很常常的,因此當背題俠是沒有用的,必需要徹底掌握瞭解題思想,並能觸類旁通才是最重要的。看到這種玩字符串又是求極值的題,想都不要想直接上DP,咱們創建一個二維數組dp,其中dp[i][j]表示字符串s1的前i個字符和字符串s2的前j個字符變相等所要刪除的字符的最小ASCII碼累加值。那麼咱們能夠先初始化邊緣,即有一個字符串爲空的話,那麼另外一個字符串有多少字符就要刪多少字符,才能變空字符串。因此咱們初始化dp[0][j]和dp[i][0],計算方法就是上一個dp值加上對應位置的字符,有點像計算累加數組的方法,因爲字符就是用ASCII表示的,因此咱們不用轉int,直接累加就能夠。這裏咱們把dp[i][0]的計算放入大的循環中計算,是爲了少寫一個for循環。好,如今咱們來看遞推公式,須要遍歷這個二維數組的每個位置即dp[i][j],當對應位置的字符相等時,s1[i-1] == s2[j-1],(注意因爲dp數組的i和j是從1開始的,因此字符串中要減1),那麼咱們直接賦值爲上一個狀態的dp值,即dp[i-1][j-1],由於已經匹配上了,不用刪除字符。若是s1[i-1] != s2[j-1],那麼就有兩種狀況,咱們能夠刪除s[i-1]的字符,且加上被刪除的字符的ASCII碼到上一個狀態的dp值中,即dp[i-1][j] + s1[i-1],或者刪除s[j-1]的字符,且加上被刪除的字符的ASCII碼到上一個狀態的dp值中,即dp[i][j-1] + s2[j-1]。這不難理解吧,好比sea和eat,當首字符s和e失配了,那麼有兩種狀況,要麼刪掉s,用ea和eat繼續匹配,或者刪掉e,用sea和at繼續匹配,記住刪掉的字符必定要累加到dp值中才行,參見代碼以下:post

 

解法一: 優化

class Solution {
public:
    int minimumDeleteSum(string s1, string s2) {
        int m = s1.size(), n = s2.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        for (int j = 1; j <= n; ++j) dp[0][j] = dp[0][j - 1] + s2[j - 1];
        for (int i = 1; i <= m; ++i) {
            dp[i][0] = dp[i - 1][0] + s1[i - 1];
            for (int j = 1; j <= n; ++j) {
                dp[i][j] = (s1[i - 1] == s2[j - 1]) ? dp[i - 1][j - 1] : min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1]);
            }
        }
        return dp[m][n];
    }
};

 

咱們也能夠優化空間複雜度,使用一個一維數組dp,其中dp[i]表示字符串s1和字符串s2的前i個字符變相等所要刪除的字符的最小ASCII碼累加值。剛開始仍是要初始化dp[j],這裏用變量t1和t2保存上一個狀態的值,並不斷更新。若是面試官沒有特別的要求,仍是用二維dp數組吧,畢竟邏輯更清晰一些,一維的容易寫錯~this

 

解法二:url

class Solution {
public:
    int minimumDeleteSum(string s1, string s2) {
        int m = s1.size(), n = s2.size();
        vector<int> dp(n + 1, 0);
        for (int j = 1; j <= n; ++j) dp[j] = dp[j - 1] + s2[j - 1];
        for (int i = 1; i <= m; ++i) {
            int t1 = dp[0];
            dp[0] += s1[i - 1];
            for (int j = 1; j <= n; ++j) {
                int t2 = dp[j];
                dp[j] = (s1[i - 1] == s2[j - 1]) ? t1 : min(dp[j] + s1[i - 1], dp[j - 1] + s2[j - 1]);
                t1 = t2;
            }
        }
        return dp[n];
    }
};

 

下面這種方法思路也很巧妙,反其道而行之,至關於先計算了字符串s1和s2的最大相同子序列,在這道題中就是最大相同子序列的ASCII碼值,而後用s1和s2的全部字符之和減去這個最大ASCII碼值的兩倍,就是要刪除的字符的最小ASCII碼值了。那麼仍是創建二維數組dp,其中dp[i][j]表示字符串s1的前i個字符和字符串s2點前j個字符中的最大相同子序列的ASCII值。而後咱們遍歷全部的位置,當對應位置的字符相等時,s1[i-1] == s2[j-1],那麼咱們直接賦值爲上一個狀態的dp值加上這個相同的字符,即dp[i-1][j-1] + s1[i-1],注意這裏跟解法一不一樣之處,由於dp的定義不一樣,因此寫法不一樣。若是s1[i-1] != s2[j-1],那麼就有兩種狀況,咱們能夠刪除s[i-1]的字符,即dp[i-1][j],或者刪除s[j-1]的字符,即dp[i][j-1],取兩者中最大值賦給dp[i][j]。最後分別算出s1和s2的累加值,減去兩倍的dp最大值便可,參見代碼以下:spa

 

解法三:code

class Solution {
public:
    int minimumDeleteSum(string s1, string s2) {
        int m = s1.size(), n = s2.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (s1[i - 1] == s2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + s1[i - 1];
                else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        int sum1 = accumulate(s1.begin(), s1.end(), 0);
        int sum2 = accumulate(s2.begin(), s2.end(), 0);
        return sum1 + sum2 - 2 * dp[m][n];
    }
};

 

相似題目:

Edit Distance

Longest Increasing Subsequence

 

參考資料:

https://discuss.leetcode.com/topic/107995/concise-dp-solution

https://discuss.leetcode.com/topic/107980/c-dp-with-explanation

https://discuss.leetcode.com/topic/108029/lcs-variation-solution-python-c

 

LeetCode All in One 題目講解彙總(持續更新中...)

相關文章
相關標籤/搜索