剑指 Offer II 096. 字符串交织(97. 交错字符串)
题目:
思路:
【1】利用递归的方式:
递归的原理:
递归本质上就是拆分,你也可以想象成树一样
如s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
本质上aad这部分是没有异议的,毕竟只有他们匹配
那么剩下的便会是s1 = "bcc", s2 = "bbca", s3 = "bbcbcac"
所以这个b应该选哪个呢?故应该两个都尝试
分为
s1填充后:s1 = "cc", s2 = "bbca", s3 = "bcbcac"
s2填充后:s1 = "bcc", s2 = "bca", s3 = "bcbcac"
那么再按这种思路一路走下去,只要有一条路可以,那么便应该返回true。
【2】动态规划的方式
代码展示:
动态规划的方式:
//时间5 ms击败36.63% //内存39.8 MB击败39.76% //标准的动态规划 //时间复杂度和空间复杂度都是 O(nm) class Solution { public boolean isInterleave(String s1, String s2, String s3) { int n = s1.length(), m = s2.length(), t = s3.length(); if (n + m != t) return false; boolean[][] f = new boolean[n + 1][m + 1]; f[0][0] = true; for (int i = 0; i <= n; ++i) { for (int j = 0; j <= m; ++j) { int p = i + j - 1; if (i > 0) { f[i][j] = f[i][j] || (f[i - 1][j] && s1.charAt(i - 1) == s3.charAt(p)); } if (j > 0) { f[i][j] = f[i][j] || (f[i][j - 1] && s2.charAt(j - 1) == s3.charAt(p)); } } } return f[n][m]; } } //当然动态规划是可以进行优化的 //时间3 ms击败63.95% //内存39.6 MB击败66.68% class Solution { public boolean isInterleave(String s1, String s2, String s3) { int n = s1.length(), m = s2.length(), t = s3.length(); if (n + m != t) return false; boolean[][] f = new boolean[n + 1][m + 1]; f[0][0] = true; for (int i = 0; i <= n; ++i) { for (int j = 0; j <= m; ++j) { int p = i + j - 1; if (i > 0) { f[i][j] = f[i][j] || (f[i - 1][j] && s1.charAt(i - 1) == s3.charAt(p)); } if (j > 0) { f[i][j] = f[i][j] || (f[i][j - 1] && s2.charAt(j - 1) == s3.charAt(p)); } } } return f[n][m]; } }
利用递归的方式:
//时间0 ms击败100% //内存39.7 MB击败56.76% //可以看出使用递归虽然能解,但是空间复杂度达不到进阶的程度 class Solution { int l1, l2, l3; String s1, s2, s3; boolean[][] visited; public boolean isInterleave(String s1, String s2, String s3) { l1 = s1.length(); l2 = s2.length(); l3 = s3.length(); if (l1 + l2 != l3) return false; visited = new boolean[l1 + 1][l2 + 1]; this.s1 = s1; this.s2 = s2; this.s3 = s3; return dfs(0, 0, 0); } private boolean dfs(int i, int j, int k) { if (k == l3) return true; if (visited[i][j]) return false; visited[i][j] = true; if (i < l1 && s1.charAt(i) == s3.charAt(k) && dfs(i + 1, j, k + 1)) return true; if (j < l2 && s2.charAt(j) == s3.charAt(k) && dfs(i, j + 1, k + 1)) return true; return false; } }
一开始以为是随意匹配的,然后运行的时候才发现其实是保留原本的顺序,也就是在相对顺序不变的情况下进行组合(这个代码其实是不过的):
如:输入"aabcc" 和 "dbbca" 和 "aadbbbaccc" 发现相对顺序不行是不过的,虽然字符都能一一对应
class Solution { public boolean isInterleave(String s1, String s2, String s3) { if (s3 == "" && s1 == "" && s2 == "") return true; int[] flag = new int[26]; int index1 = 0, index2 = 0; while (index1 < s1.length() || index2 < s2.length()){ if (index1 < s1.length()) flag[s1.charAt(index1++) - 'a']++; if (index2 < s2.length()) flag[s2.charAt(index2++) - 'a']++; } for (int i = 0; i < s3.length(); i++){ if (--flag[s3.charAt(i) - 'a'] < 0) return false; } return true; } }