给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
示例 1:
输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出: true
示例 2:
输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
输出: false
方法一:简单的暴力回朔
class Solution {
boolean flag=false;
int len1,len2,len3;
public boolean isInterleave(String s1, String s2, String s3) {
if(s3.length()!=s1.length()+s2.length())
return false;
int[] nums=new int[26];
for(int i=0;i<s3.length();i++)
nums[s3.charAt(i)-'a']++;
for(int i=0;i<s1.length();i++)
nums[s1.charAt(i)-'a']--;
for(int i=0;i<s2.length();i++)
nums[s2.charAt(i)-'a']--;
for(int i=0;i<26;i++)
if(nums[i]!=0)
return false;
len1=s1.length();
len2=s2.length();
len3=len1+len2;
dfs(s1,s2,s3,0,0,0);
return flag;
}
private void dfs(String s1,String s2,String s3,int x,int y,int z)
{
if(flag) return;
if(z==len3)
{
flag=true;
return;
}
if(x<len1 && s1.charAt(x)==s3.charAt(z))
dfs(s1,s2,s3,x+1,y,z+1);
if(y<len2 && s2.charAt(y)==s3.charAt(z))
dfs(s1,s2,s3,x,y+1,z+1);
}
}
方法二:记忆化搜索,我们知道方法一中的回朔是存在很多冗余次数的回朔,一些可能的情况完全没有必要再遍历,因此我们可以开一个二维数组存一下已经得出答案的子串的情况。
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
int memo[][] =new int[s1.length()][s2.length()];
for(int i=0;i<s1.length();i++)
for(int j=0;j<s2.length();j++)
memo[i][j]=-1;
return dfs(s1,0,s2,0,s3,0,memo);
}
private boolean dfs(String s1,int i,String s2,int j,String s3,int k,int[][] memo)
{
if(i==s1.length())
return s2.substring(j).equals(s3.substring(k));
if(j==s2.length())
return s1.substring(i).equals(s3.substring(k));
if(memo[i][j]>=0)
return memo[i][j]==1?true:false;
boolean ans=false;
if(s3.charAt(k)==s1.charAt(i) && dfs(s1,i+1,s2,j,s3,k+1,memo) || s3.charAt(k)==s2.charAt(j) && dfs(s1,i,s2,j+1,s3,k+1,memo))
ans=true;
memo[i][j]=ans?1:0;
return ans;
}
}
方法三:动态规划
前两种方法我们都是枚举以第一个串的i开头或者以第二个串的j开头组成的后缀串是否与第三个串的后缀相同,我们可以考虑第一个串以i结尾,第二个串以j结尾的串的前缀和第三个串以k为前缀的串是否匹配。
发现题解讲的非常好,因此我直接贴出截图:
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if(s3.length()!=s1.length()+s2.length())
return false;
boolean[][] dp=new boolean[s1.length()+1][s2.length()+1];
for(int i=0;i<=s1.length();i++)
for(int j=0;j<=s2.length();j++)
{
if(i+j==0)
dp[i][j]=true;
else if(i==0)
dp[i][j]=dp[i][j-1] && s2.charAt(j-1)==s3.charAt(i+j-1);
else if(j==0)
dp[i][j]=dp[i-1][j] && s1.charAt(i-1)==s3.charAt(i+j-1);
else
dp[i][j]=dp[i-1][j] && s1.charAt(i-1)==s3.charAt(i+j-1) || dp[i][j-1] && s2.charAt(j-1)==s3.charAt(i+j-1);
}
return dp[s1.length()][s2.length()];
}
}
方法四:对于第三种方法我们可以做进一步的优化,将二维数组降到一维。
class Solution {
public boolean isInterleave(String s1, String s2, String s3) {
if(s3.length()!=s1.length()+s2.length())
return false;
boolean[] dp=new boolean[s2.length()+1];
for(int i=0;i<=s1.length();i++)
for(int j=0;j<=s2.length();j++)
{
if(i+j==0)
dp[j]=true;
else if(i==0)
dp[j]=dp[j-1] && s2.charAt(j-1)==s3.charAt(i+j-1);
else if(j==0)
dp[j]=dp[j] && s1.charAt(i-1)==s3.charAt(i+j-1);
else
dp[j]=dp[j] && s1.charAt(i-1)==s3.charAt(i+j-1) || dp[j-1] && s2.charAt(j-1)==s3.charAt(i+j-1);
}
return dp[s2.length()];
}
}