赞
踩
72. 编辑距离
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
插入一个字符
删除一个字符
替换一个字符
示例 1:
输入:word1 = “horse”, word2 = “ros”
输出:3
解释:
horse -> rorse (将 ‘h’ 替换为 ‘r’)
rorse -> rose (删除 ‘r’)
rose -> ros (删除 ‘e’)
示例 2:
输入:word1 = “intention”, word2 = “execution”
输出:5
解释:
intention -> inention (删除 ‘t’)
inention -> enention (将 ‘i’ 替换为 ‘e’)
enention -> exention (将 ‘n’ 替换为 ‘x’)
exention -> exection (将 ‘n’ 替换为 ‘c’)
exection -> execution (插入 ‘u’)
提示:
0 <= word1.length, word2.length <= 500
word1 和 word2 由小写英文字母组成
还是按照DP三部曲来判断
最少操作步骤,是最值问题
给定一个单词,转换为另外一个单词
最后一步只有上面三种情况
假设,前面的工作都做好,最后一步是插入一个字符
假设,前面的工作都做好,最后一步是删除一个字符
假设,前面的工作都做好,最后一步是替换一个字符
class Solution { public int minDistance(String word1, String word2) { //边界值 if(word1 == null || word2 == null) return 0; char[] word1CharArray = word1.toCharArray(); char[] word2CharArray = word2.toCharArray(); int word1Length = word1CharArray.length; int word2Length = word2CharArray.length; //dp的长度为word1的长度+1 int[][] dp = new int[word1Length + 1][word2Length + 1]; dp[0][0] = 0; //行为0 for(int col = 1; col <= word2Length; col++){ dp[0][col] = col; } //列为0 for(int row = 1; row <= word1Length; row++){ dp[row][0] = row; } for(int row = 1; row <= word1Length; row++){ for(int col = 1; col <= word2Length; col++){ //从上到下 int topToBottom = dp[row - 1][col] + 1; //从左到右 int leftToRight = dp[row][col - 1] + 1; //从左上到右下 int leftTopToRightBottom = dp[row - 1][col - 1] + 1; if(word1CharArray[row - 1] == word2CharArray[col - 1]){ leftTopToRightBottom = dp[row - 1][col - 1]; } dp[row][col] = Math.min(Math.min(topToBottom, leftToRight), leftTopToRightBottom); } } return dp[word1Length][word2Length]; } }
注意
两层for循环的时候,还是从1开始,而不是从2开始,因为dp[1][1]前面是没有求的
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: “babad”
输出: “bab”
注意: “aba” 也是一个有效答案。
示例 2:
输入: “cbbd”
输出: “bb”
需要借助两个指针,左边一个指针,右边一个指针。判断两个值是否相等,相等则做相应的加法与减法,不相等则不是回文子串
两个for循环,时间复杂度为O(n^2)
每一个区间都需要判断是否是回文子串,都需要O(n)
因此,整体时间复杂度为O(n^3)
class Solution { public String longestPalindrome(String s) { //边界值 if(s == null) return null; if(s.length() == 0) return ""; char[] sArray = s.toCharArray(); ArrayList list = new ArrayList(); int max = 0; int resultLeft = 0; int resultRight = 0; for(int left = 0; left < sArray.length; left++){ for(int right = left; right < sArray.length; right++){ if(isHuiWenChuan(sArray, left, right)){ if(max < right - left + 1){ max = right - left + 1; resultLeft = left; resultRight = right; } } } } return new String(sArray, resultLeft, resultRight - resultLeft + 1); } private boolean isHuiWenChuan(char[] sArray, int left, int right) { int i = left; int j = right; while(i < j){ if(sArray[i] == sArray[j]){ i++; j--; }else{ return false; } } return true; } }
注意:
char[] sArray = s.toCharArray();是char[] 不是int[]
字符串与数组的转换:
字符串转数组
数组转字符串
DP三大步骤:
最长回文子串,是
确定dp含义
dp[i][j]表示字符串s从i到j是不是回文子串
注意,dp[i][j]存储的是和否
确定边界值
dp[0][0]、dp[1][1]、dp[2][2]、…、dp[k][k] = true;
确定状态转移方程
假如现在已知dp[i - 1][j]的结果,能推出dp[i][j]的结果吗?
假如现在已知dp[i][j - 1]的结果,能推出dp[i][j]的结果吗?
如果有字符串aba,已知ab不是回文,那么aba是回文
如果有字符串abc,已知ab不是回文,那么abc不是回文
如果有字符串aaa,已知aa是回文,那么aaa是回文
如果有字符串aab,已知aa是回文,那么aab不是回文
并不能通过前面的dp[i - 1][j]或dp[i][j - 1]的结果推出dp[i][j]的结果,那,
分两种情况考虑:
如果s[i, j]的长度:j - i + 1 <= 2
<=2那么,只有0,1,2
0的情况已经在开始排除
1的情况也已经考虑过dp[i, i] = true;
那么,剩下的只有长度为2
如果j - i + 1 = 2
那么dp[i, j] = s[i] == s[j];并且,长度为1的时候,也可以使用这个公式
如果s[i, j]的长度:j - i + 1 > 2
如果s[i + 1, j - 1]是回文子串,且s[i] == s[j],那么s[i, j]是回文子串
dp[i, j] = dp[i + 1, j - 1] && s[i] == s[j];
左下角的值,推到出右上角的值
class Solution { public String longestPalindrome(String s) { //边界值 if(s == null) return null; if(s.length() == 0) return ""; //字符转数组 char[] sArray = s.toCharArray(); //建立dp,里面存储的是true,false boolean [][] dp = new boolean[sArray.length][sArray.length]; int left = 0; int maxlength = 1; //先求左下,再求右上,这就要求i需要从大到小,j从小到大 for(int i = sArray.length - 1; i>=0; i--){ for(int j = i; j<sArray.length; j++){ if(j - i + 1 <= 2){ dp[i][j] = (sArray[i] == sArray[j]); }else{ dp[i][j] = dp[i + 1][j - 1] && (sArray[i] == sArray[j]); } if(dp[i][j] && (maxlength < j - i + 1)){ maxlength = j - i + 1; left = i; } } } return new String(sArray, left, maxlength); } }
注意:
dp[i, j] = dp[i + 1, j - 1] && s[i] == s[j];
先求左下,再求右上
这就要求i需要从大到小,j从小到大
以某一个点为中心,左右扩展,左右相等,则是回文子串(下图左)
但,这些子串都是奇数个,回文子串的偶数个没有被计算,因此,需要借助元素之间的间隙,左右扩展,从而找出偶数类型的回文子串(下图右)
假设字符串“abbaba”的长度为n,那么,可以作为扩展中心的个数为:n + (n - 1) = 2*n - 1
时间复杂度为O((2n - 1) * n) = O(2n^2 - n) = O(n ^2)
空间复杂度为O(1)
class Solution { public String longestPalindrome(String s) { //边界值 if(s == null) return null; if(s.length() == 0) return s; char[] sArray = s.toCharArray(); ArrayList list = new ArrayList(); int max = 1; int begin = 0; for(int i = 0; i < sArray.length; i++){ int left = i; int right = i; int count = 1; while(--left >= 0 && ++right < sArray.length){ if(sArray[left] == sArray[right]){ count = count + 2; if(max < count){ max = count; begin = left; } }else{ break; } } } for(int i = 0; i < sArray.length - 1; i++){ int left = i; int right = i + 1; int count = 0; while(left >= 0 && right < sArray.length){ if(sArray[left] == sArray[right]){ count = count + 2; if(max < count){ max = count; begin = left; } }else{ break; } left--; right++; } } return new String(sArray, begin, max); } }
略
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。