leetcode 97:交錯字串
阿新 • • 發佈:2020-07-18
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);
}