Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc"
,
s2 = "dbbca"
,
When s3 = "aadbbcbcac"
, return true.
When s3 = "aadbbbaccc"
, return false.
给定三个字符串,判断第三个字符串是否由前两个字符串组合而成(互相插入,即相对顺序不变。)
1、第一次写的是贪心算法,但是超时了。
public class Solution { public boolean isInterleave(String s1, String s2, String s3) { if( s1.length()+s2.length() != s3.length()) return false; if( s1.length()+s2.length() != s3.length()) return false; if( s1.length() == 0) return s2.equals(s3); if( s2.length() == 0) return s1.equals(s3); System.out.println(s1.length()+" "+s2.length()+" "+s3.length() ); return getResult(s1,s2,s3,0,0,0); } public boolean getResult(String s1,String s2,String s3,int i,int j,int k){ if( i == s1.length() && j == s2.length() && k == s3.length()) return true; else if( i == s1.length() ){ while( j<s2.length() && s2.charAt(j) == s3.charAt(k)){ j++; k++; } if( j == s2.length() ) return true; else return false; }else if( j == s2.length() ){ while( i<s1.length() && s1.charAt(i) == s3.charAt(k)){ i++; k++; } if( i == s1.length() ) return true; else return false; }else if( s1.charAt(i) == s3.charAt(k) && s2.charAt(j) != s3.charAt(k)) return getResult(s1,s2,s3,i+1,j,k+1); else if( s2.charAt(j) == s3.charAt(k) && s1.charAt(i) != s3.charAt(k)) return getResult(s1,s2,s3,i,j+1,k+1); else if( s1.charAt(i) == s3.charAt(k) && s2.charAt(j) == s3.charAt(k)){ boolean res = getResult(s1,s2,s3,i+1,j,k+1); if( res ) return true; res = getResult(s1,s2,s3,i,j+1,k+1); return res?true:false; }else return false; } }
2、所以使用DP算法
这里就类似于一个二维的地图,判断是否能从左上角走到右下角。
示例:s1="aa",s2="ab",s3="aaba"。标1的为可行。最终返回右下角。
0 a b
0 1 1 0
a 1 1 1
a 1 0 1
最后AC,但是并不算太快。
public class Solution { public boolean isInterleave(String s1, String s2, String s3) { if( s1.length()+s2.length() != s3.length()) return false; if( s1.length() == 0) return s2.equals(s3); if( s2.length() == 0) return s1.equals(s3); boolean[][] result = new boolean[s1.length()+1][s2.length()+1]; result[0][0] = true; for( int i = 0;i<=s1.length();i++){ for( int j = 0;j<=s2.length();j++){ if( i == 0 && j == 0) result[i][j] = true; else if( j == 0){ result[i][0] = result[i-1][0] && s1.charAt(i-1) == s3.charAt(i-1); }else if( i == 0){ result[0][j] = result[0][j-1] && s2.charAt(j-1) == s3.charAt(j-1); } else{ if( result[i-1][j] && s1.charAt(i-1) == s3.charAt(i+j-1)) result[i][j] = true; else if( result[i][j-1] && s2.charAt(j-1) == s3.charAt(i+j-1)) result[i][j] = true; } } } return result[s1.length()][s2.length()]; } }
3、可以在空间上稍微简化一下,使用单数组完成。只是稍作改变,就不再贴出来了。
4、第三种方法是将上述两种方法结合一下,可以达到1ms,最快,这里是借鉴了Discuss里面的一个答案。
public class Solution { public boolean isInterleave(String s1, String s2, String s3) { int[][] memo = new int[s1.length() + 1][s2.length() + 1]; return helper(s1, s2, s3, 0, 0, 0, memo); } private boolean helper(String s1, String s2, String s3, int index1, int index2, int index3, int[][] memo) { if(s1.length() + s2.length() != s3.length()) return false; if(s1.length() == index1 && s2.length() == index2 && s3.length() == index3 ) return true; boolean s1flag = false; boolean s2flag = false; if(index1 < s1.length() && s1.charAt(index1) == s3.charAt(index3)) { if(memo[index1+1][index2] == 1) { s1flag = true; } else if(memo[index1][index2] == 0){ s1flag = helper(s1, s2, s3, index1+1, index2, index3+1, memo); memo[index1+1][index2] = s1flag ? 1 : -1; } } if(index2 < s2.length() && s2.charAt(index2) == s3.charAt(index3)) { if(memo[index1][index2+1] == 1) { s2flag = true; } else if(memo[index1][index2] == 0){ s2flag = helper(s1, s2, s3, index1, index2 + 1, index3 + 1, memo); memo[index1][index2+1] = s1flag ? 1 : -1; } } return s1flag || s2flag; } }