LeetCode题解系列--712. Minimum ASCII Delete Sum for Two Strings

来源:互联网 发布:淘宝vip课程免费下载 编辑:程序博客网 时间:2024/06/05 09:45

描述

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

Example 1:
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].
难度:medium

思路

这是一道使用DP的问题,对于DP的问题,最重要的是找到合适的状态和状态转移方程。一开始我也卡在这里,其实直接使用题目要得到的答案作为状态就行了。
题目所求为使得两个字符串ascii和相同的最小删除字符ascii和,所以我们直接设C[i][j] 为s1 前 i个字符与s2 前j个字符得到题目要求所需删除的字符和。
那么我们开始构造转移方程:
对于s1[0...i1]s2[0...j1] 所需要删除的和应该是这样的:

  1. s1[i1]==s2[j1] ,则C[i][j]=C[i1][j1]
  2. 若不相等,则s1[i1], s2[j1] 选择删除一个,
    C[i][j]=min(C[i1][j]+s1[i1],C[i][j1]+s2[j1])
    这里应该还是比较容易理解的,从这个字符选择一个能够得到较小的C[i][j] 值的删除。

普通的解答

class Solution {public:    int minimumDeleteSum(string s1, string s2) {        vector<vector<int> > C(s1.length() + 1, vector<int>(s2.length() + 1, 0));        // initial        for (int i = 1; i < s2.length() + 1; ++i) {            C[0][i] = C[0][i - 1] + s2[i - 1];        }        for (int i = 1; i < s1.length() + 1; ++i) {            C[i][0] = C[i - 1][0] + s1[i - 1];        }        for (int i = 1; i < s1.length() + 1; ++i) {            for (int j = 1; j < s2.length() + 1; ++j) {                if (s1[i - 1] == s2[j - 1]) {                    C[i][j] =  C[i - 1][j - 1];                } else {                    // delete s1[i-1] or s2[j-1]                    C[i][j] = min(C[i - 1][j] + s1[i - 1], C[i][j - 1] + s2[j - 1]);                }            }        }        return C[s1.length()][s2.length()];    }};

这种解答的空间复杂度为O(mn)
显然这是可以优化的

优化空间复杂度

通过观察内层循环我们可以发现,对于每个C[i][j]的求解其依赖于C[i1][j1],C[i1][j],C[i][j1]
那么首先可以得出这样一种思路,就是原先的mn 数组其实只需要两行就足够了,因为对于每个新状态其只依赖于第i行和第i-1行的数据。
再深入想,其实对于第i-1行,其只需要C[i1][j]C[i1][j1] 两项。
现在我们假定我们使用一个一维的数组来保存状态以完成该动态规划问题
那么我们假定当j=1 时,即一次全新的内层循环刚开始的时候,此一维数组保存的是i1 时的状态,那么我们可以知道关于j的循环结束之后,此一维数组应该保存的是i 时的状态,那么我们在计算C[i][j] 的时候只需要保存好上一外层循环C[i1][j]C[i1][j1] 两项。


对于DP问题优化空间使用是很常见的,我希望能够总结出一个通用的思路,但发现上面的解释还是很不清晰。


优化后的结果:

class Solution {public:    int minimumDeleteSum(string s1, string s2) {        vector<int> C(s2.length() + 1, 0);        // temp_j : C[i-1][j]        // temp_j_one : C[i - 1][j - 1]         int temp_j, temp_j_one;        for (int i = 1; i < s2.length() + 1; ++i) {            C[i] = C[i - 1] + s2[i - 1];        }        for (int i = 1; i < s1.length() + 1; ++i) {            temp_j_one = C[0];            C[0] += s1[i - 1];            for (int j = 1; j < s2.length() + 1; ++j) {                temp_j = C[j];                if (s1[i - 1] == s2[j - 1]) {                    C[j] = temp_j_one;                } else {                    C[j] = min(temp_j + s1[i - 1], C[j - 1] + s2[j - 1]);                }                temp_j_one = temp_j;            }        }        return C[s2.length()];    }};

点击这里查看更多我的leetcode答案

阅读全文
0 0
原创粉丝点击