package com.example.lettcode.dailyexercises;
/**
* @Class IsInterleave
* @Description 97 交错字符串
* 给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
* <p>
* 示例 1:
* 输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
* 输出: true
* <p>
* 示例 2:
* 输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
* 输出: false
* @Author
* @Date 2020/7/18
**/
public class IsInterleave {
}
/**
* error
* 双指针
* 这种方式有可能因为前面交替顺序不对,导致结果不对,应该加上回溯
* s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
* 当出现当前位置分别指向s1[5],s2[3],s3[8]时导致后面无法交替下去
*/
/* public static boolean isInterleave(String s1, String s2, String s3) {
boolean flag = false;
if (s3.length() != (s1.length() + s2.length())) return false;
int len1 = s1.length();
int len2 = s2.length();
int len3 = s3.length();
int p1 = 0, p2 = 0, p3 = 0;
while ((p1 < len1 || p2 < len2) && p3 < len3) {
if ((p1 < len1) && s3.charAt(p3) == s1.charAt(p1)) {
p3++;
p1++;
} else if ((p2 < len2) && s3.charAt(p3) == s2.charAt(p2)) {
p3++;
p2++;
} else {
return false;
}
}
return flag;
}*/
/**
* 双指针+回溯
*/
public static boolean isInterleave(String s1, String s2, String s3) {
if (s1.length() + s2.length() != s3.length()) return false;
return canMatch(s1, 0, s2, 0, s3, 0);
}
public static boolean canMatch(String s1, int p1, String s2, int p2, String s3, int p3) {
if (p3 >= s3.length()) return true;
if ((p1 < s1.length()) && (p3 < s3.length())
&& (s1.charAt(p1) == s3.charAt(p3))
&& (canMatch(s1, p1 + 1, s2, p2, s3, p3 + 1))) {
System.out.println(s1.charAt(p1) +" "+s3.charAt(p3));
return true;
}
if ((p2 < s2.length()) && (p3 < s3.length())
&& (s2.charAt(p2) == s3.charAt(p3))
&& (canMatch(s1, p1, s2, p2 + 1, s3, p3 + 1))) {
System.out.println(s2.charAt(p2) +" "+s3.charAt(p3));
return true;
}
return false;
}
/**
* 动态规划:二维实现方式
* dp[i][j] = dp[i-1][j] &&s1(i)=s3(i+j) 或者dp[i][j-1] &&s2[j]=s3[i+j]
* dp[0][0] = true
* 时间和空间复杂度均为O(MN)
*/
public static boolean isInterleave(String s1, String s2, String s3) {
if (s3.length() != (s1.length() + s2.length())) return false;
int len1 = s1.length();
int len2 = s2.length();
// dp[i][j] 表示s1[i]和s2[j] 是否能交替组成s3[i+j]
boolean[][] dp = new boolean[len1 + 1][len2 + 1];
// 边界条件为啥是true,dp[0][1]/dp[1][0]可以为true,其前提条件之一是dp[0][0]为true
dp[0][0] = true;
for (int i = 0; i <= len1; ++i) {
for (int j = 0; j <= len2; ++j) {
int p = i + j - 1; // s3的位置
//方式1--start,分别使用i>0 和j>0 是因为会有i>0&&j=0 或者i=0&&j>0 的情况
// if (i > 0) {
// dp[i][j] = dp[i][j] || (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(p));
// }
// if (j > 0) {
// dp[i][j] = dp[i][j] || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(p));
// }
// 方式1--end
// 方式2--start
if (p < 0) continue;
// 使用这种方式会导致dp[0][0] 被修改为false,添加continue语句,可以避免这种情况
dp[i][j] = (((i > 0) && (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(p)))
|| ((j > 0) && (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(p))));
// 方式2--end
}
}
return dp[len1][len2];
}
/**
* 动态规划优化空间: 滚动数组
*/
public static boolean isInterleave(String s1, String s2, String s3) {
if (s3.length() != (s1.length() + s2.length())) return false;
int len1 = s1.length();
int len2 = s2.length();
// dp[j] 表示s1[i]和s2[j] 是否能交替组成s3[i+j]
boolean[] dp = new boolean[len2 + 1];
// 边界条件为啥是true,dp[1]可以为true,其前提条件之一是dp[0]为true
dp[0] = true;
for (int i = 0; i <= len1; ++i) {
for (int j = 0; j <= len2; ++j) {
int p = i + j - 1; // s3的位置
if (p < 0) continue;
// 使用这种方式会导致dp[0]被修改为false,添加continue语句,可以避免这种情况
dp[j] = (((i > 0) && (dp[j] && s1.charAt(i - 1) == s3.charAt(p)))
|| ((j > 0) && (dp[j - 1] && s2.charAt(j - 1) == s3.charAt(p))));
}
}
return dp[len2];
}
public static void main(String[] args) {
String s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac";
boolean ans = isInterleave(s1, s2, s3);
System.out.println("IsInterleave demo01 result:" + ans);
s1 = "aabcc";
s2 = "dbbca";
s3 = "aadbbbaccc";
ans = isInterleave(s1, s2, s3);
System.out.println("IsInterleave demo02 result:" + ans);
}