题目
给定一个字符串 s1,我们可以把它递归地分割成两个非空子字符串,从而将其表示为二叉树。
下图是字符串 s1 = "great" 的一种可能的表示形式。
great
/
gr eat
/ /
g r e at
/
a t
在扰乱这个字符串的过程中,我们可以挑选任何一个非叶节点,然后交换它的两个子节点。
例如,如果我们挑选非叶节点 "gr" ,交换它的两个子节点,将会产生扰乱字符串 "rgeat" 。
rgeat
/
rg eat
/ /
r g e at
/
a t
我们将 "rgeat” 称作 "great" 的一个扰乱字符串。
同样地,如果我们继续交换节点 "eat" 和 "at" 的子节点,将会产生另一个新的扰乱字符串 "rgtae" 。
rgtae
/
rg tae
/ /
r g ta e
/
t a
我们将 "rgtae” 称作 "great" 的一个扰乱字符串。
给出两个长度相等的字符串 s1 和 s2,判断 s2 是否是 s1 的扰乱字符串。
示例 1:输入: s1 = "great", s2 = "rgeat" 输出: true
示例 2:输入: s1 = "abcde", s2 = "caebd" 输出: false
解题思路分析
1、动态规划;时间复杂度O(n^4),空间复杂度O(n^3)
![f0df89d85f3e633d39ea806ea2d27481.png](https://i-blog.csdnimg.cn/blog_migrate/9d05b2d73a4a1ef5b76c3f21772a85fe.jpeg)
func isScramble(s1 string, s2 string) bool {n, m := len(s1), len(s2)if n != m {return false}// dp[i][j][l]:表示s1从i开始,s2从j开始长度为l的两个子字符串是扰乱dp := make([][][]bool, n+1)for i := 0; i <= n; i++ {dp[i] = make([][]bool, n+1)for j := 0; j <= n; j++ {dp[i][j] = make([]bool, n+1)}}// 单个字符for i := 0; i < n; i++ {for j := 0; j < n; j++ {dp[i][j][1] = s1[i] == s2[j]}}for k := 2; k <= n; k++ { // 枚举长度: 2-nfor i := 0; i <= n-k; i++ { // s1起点for j := 0; j <= n-k; j++ { // s2起点dp[i][j][k] = false// 长度为w,分为两部分,其中最少是1for w := 1; w <= k-1; w++ {// 划分不交换:S1->T1, S2->T2// 划分交换: S1->T2, S2->T1if (dp[i][j][w] == true && dp[i+w][j+w][k-w] == true) ||(dp[i][j+k-w][w] == true && dp[i+w][j][k-w] == true) {dp[i][j][k] = true}}}}}return dp[0][0][n]}
2、递归;时间复杂度O(5^n),空间复杂度O(n)
func isScramble(s1 string, s2 string) bool {return dfs([]byte(s1), []byte(s2))}func dfs(arr1, arr2 []byte) bool {if compare(arr1, arr2) == false {return false}if len(arr1) <= 2 {return (len(arr1) == 2 && ((arr1[0] == arr2[0] && arr1[1] == arr2[1]) ||(arr1[0] == arr2[1] && arr1[1] == arr2[0]))) ||(len(arr1) == 1 && arr1[0] == arr2[0])}for i := 1; i < len(arr1); i++ {leftA, rightA := arr1[:i], arr1[i:]leftB, rightB := arr2[:i], arr2[i:]LB, RB := arr2[len(arr1)-i:], arr2[:len(arr1)-i]if (dfs(leftA, leftB) && dfs(rightA, rightB)) || (dfs(leftA, LB) && dfs(rightA, RB)) {return true}}return false}func compare(arr1, arr2 []byte) bool {if len(arr1) != len(arr2) {return false}arrA := make([]byte, 26)arrB := make([]byte, 26)for i := 0; i < len(arr1); i++ {arrA[arr1[i]-'a']++arrB[arr2[i]-'a']++}for i := 0; i < len(arrA); i++ {if arrA[i] != arrB[i] {return false}}return true}
总结
Hard题目,考察字符串动态规划解法