中山 网站建设一条龙服务苹果cms永久免费全能建站程序
刷题记录
- *115. 不同的子序列
- 583. 两个字符串的删除操作
- 思路一:转求公共子序列
- 思路二:编辑距离(统计删除次数)
- 72. 编辑距离
*115. 不同的子序列
leetcode题目地址
编辑距离问题。
题目要求在s
串中查找t
串出现的次数。
dp数组含义:dp[i][j] 表示以s[i-1]
结尾的子串A中出现以t[j-1]
为结尾的子串B的个数
状态转移方程:
题目要求在s
串中查找t
串出现的次数,因此只考虑对s
串进行编辑。
- 当
s[i-1] == t[j-1]
时,dp[i][j] = dp[i-1][j-1] + dp[i-1][j],分别考察使用s[i-1]
和不使用s[i-1]
- dp[i-1][j-1]:(使用s[i-1])以
s[i-2]
结尾的子串A中出现以t[j-2]
为结尾的子串B的个数,也就是不考虑当前s串和t串
正在查看的当前字符,查看两个子串前一位的匹配情况(就是考虑将当前字符加入子串) - dp[i-1][j-1]:(不使用s[i-1])以
s[i-2]
结尾的子串A中出现以t[j-1]
为结尾的子串B的个数,也就是不考虑当前s串
正在查看的当前字符,即删除s[i-1]
- dp[i-1][j-1]:(使用s[i-1])以
时间复杂度: O ( n ∗ m ) O(n*m) O(n∗m)
空间复杂度: O ( n ∗ m ) O(n*m) O(n∗m)
// java
class Solution {public int numDistinct(String s, String t) {int len1 = s.length(), len2 = t.length();char[] sArray = s.toCharArray(), tArray = t.toCharArray();int[][] dp = new int[len1+1][len2+1];for(int i=0; i<=len1; i++) dp[i][0] = 1;int result = 0;for(int i=1; i<=len1; i++){for(int j=1; j<=len2; j++){if(sArray[i-1] == tArray[j-1]){dp[i][j] = dp[i-1][j-1] + dp[i-1][j];} else {dp[i][j] = dp[i-1][j];}}} return dp[len1][len2] % (int)(Math.pow(10, 9)+7);}
}
583. 两个字符串的删除操作
leetcode题目地址
思路一:转求公共子序列
同样是编辑距离问题。
本题仅考虑删除问题,因此较简单。
先将问题转化:
- 原问题:每步可以删除任意一个字符串中的一个字符。
- 转化:先求两个字符串的公共子序列长度,然后两个子序列中各自多出来的其余字符就是要删除的。
统计公共子序列长度公共子序列长度是前面做过的(题解),因此直接把代码搬过来既可。
题目要求返回两个字符串总共删除的字符个数,设公共子序列长度为x,则A、B串中各自有长为x的子串,因此要删除的字符总数 = A串长度 + B串长度 - x * 2
时间复杂度: O ( n ∗ m ) O(n * m) O(n∗m)
空间复杂度: O ( n ∗ m ) O(n * m) O(n∗m)
// java
class Solution {public int minDistance(String word1, String word2) {char[] arr1 = word1.toCharArray(), arr2 = word2.toCharArray();int len1 = arr1.length, len2 = arr2.length;// dp[i][j]:以s[i-1]和t[j-1]的两个子串公共子序列长度int[][] dp = new int[len1+1][len2+1];// 状态转移方程:// s[i-1]==t[j-1]: dp[i][j] = dp[i-1][j-1] + 1;// s[i-1]!=t[j-1]: dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);for(int i=1; i<=len1; i++){for(int j=1; j<=len2; j++){if(arr1[i-1] == arr2[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]*2;}
}
思路二:编辑距离(统计删除次数)
dp数组含义:dp[i][j]表示以word1[i-1]和word2[j-1]结尾的相同子串需要删除的最小步数
状态转移方程:
- word1[i-1] == word2[j-1]:
dp[i][j] = dp[i-1][j-1]
- word1[i-1] != word2[j-1]:
- 删除word1[i-1]:dp[i-1][j] + 1
- 删除word2[j-1]:dp[i][j-1] + 1
- 删除word1[i-1]和word2[j-1]:dp[i-1][j-1] + 2
综上,dp[i][j]更新为三者取最小,即:
dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 2)
PS: 这里dp[i-1][j-1] + 2其实相当于dp[i][j-1] + 1或dp[i-1][j],用dp[i][j-1] + 1举例:
dp[i][j-1] + 1是考虑word1[i-1]和不考虑word2[j-1],在这个基础上再不考虑word1[i-1]就是dp[i-1][j-1] + 1 + 1也就是dp[i-1][j-1] + 2,因此在第二部两字符不相等时,更新dp[i][j]仅需要比较两个串各自不考虑当前字符即可,即:dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1)
// java
class Solution {public int minDistance(String word1, String word2) {char[] arr1 = word1.toCharArray(), arr2 = word2.toCharArray();int len1 = arr1.length, len2 = arr2.length;int[][] dp = new int[len1+1][len2+1];// dp数组含义:dp[i][j]表示以s[i-1]和t[j-1]结尾的相同子串需要删除的最小步数// 状态转移方程// s[i-1] == t[j-1]: dp[i][j] = dp[i-1][j-1]// s[i-1] != t[j-1]: // dp[i-1][j] + 1// dp[i][j-1] + 1// dp[i-1][j-1] + 2// dp[i][j] = Math.min(Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + 2)// 初始化// dp[0][j] = j dp[i][0] = ifor(int i=0; i<=len1; i++) dp[i][0] = i;for(int j=0; j<=len2; j++) dp[0][j] = j;for(int i=1; i<=len1; i++){for(int j=1; j<=len2; j++){if(arr1[i-1] == arr2[j-1]){dp[i][j] = dp[i-1][j-1];}else{dp[i][j] = Math.min(Math.min(dp[i-1][j]+1, dp[i][j-1]+1), dp[i-1][j-1]+2);}}}return dp[len1][len2];}
}
72. 编辑距离
leetcode题目地址
dp数组含义:dp[i][j]表示以word1[i-1]和word2[j-1]结尾的相同串所需最少操作数
状态转移方程:
- word1[i-1]==word2[j-1]:
dp[i][j] = dp[i-1][j-1]
- word1[i-1]!=word2[j-1]:
- 删除word1[i-1](也就是word1[i-2]和word2[j-1]匹配,word1[i-1]多余): dp[i][j] = dp[i-1][j] + 1
- 向word1插入word2[j-1](也就是word1[i-1]和word2[j-2]匹配,但当前word2[j-1]缺少匹配): dp[i][j] = dp[i][j-1] + 1
- 替换word1[i-1]为word2[j-1](也就是word1[i-2]和word2[j-2]匹配,但word1[i-1]和word2[j-1]不匹配):dp[i][j] = dp[i-1][j-1] + 1
综上,三者取最小,即:
dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 1)
初始化:dp[i][0] = i, dp[0][j] = j
时间复杂度: O ( n ∗ m ) O(n*m) O(n∗m)
空间复杂度: O ( n ∗ m ) O(n*m) O(n∗m)
// javaclass Solution {public int minDistance(String word1, String word2) {char[] arr1 = word1.toCharArray(), arr2 = word2.toCharArray();int len1 = arr1.length, len2 = arr2.length;int[][] dp = new int[len1+1][len2+1];// dp数组含义:dp[i][j]表示以word1[i-1]和word2[j-1]结尾的相同串所需最少操作数// 状态转移方程:// word1[i-1]==word2[j-1]: dp[i][j] = dp[i-1][j-1]// word1[i-1]!=word2[j-1]: // 删除word1[i-1]: dp[i][j] = dp[i-1][j] + 1// 向word1插入word2[j-1]: dp[i][j] = dp[i][j-1] + 1// 替换word1[i-1]为word2[j-1]:dp[i][j] = dp[i-1][j-1] + 1// 三者取最小// 初始化:dp[i][0] = i dp[0][j] = jfor(int i=0; i<=len1; i++) dp[i][0] = i;for(int j=0; j<=len2; j++) dp[0][j] = j;for(int i=1; i<=len1; i++){for(int j=1; j<=len2; j++){if(arr1[i-1] == arr2[j-1]){dp[i][j] = dp[i-1][j-1];} else{dp[i][j] = Math.min(Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1), dp[i-1][j-1] + 1);}}}return dp[len1][len2];}
}