87. Scramble String

问题:

求给定的两个字符串S1和S2是否 S1能经过以下变换得到S2。

若字符串长度为1,直接返回。

  • 从任意index,进行切分,pre和post两部分,
  • 可以选择:是否对这两部分进行交换。

然后,再将分割后的两部分,分别作为对象字符串,重复上述两个操作。

Example 1:
Input: s1 = "great", s2 = "rgeat"
Output: true
Explanation: One possible scenario applied on s1 is:
"great" --> "gr/eat" // divide at random index.
"gr/eat" --> "gr/eat" // random decision is not to swap the two substrings and keep them in order.
"gr/eat" --> "g/r / e/at" // apply the same algorithm recursively on both substrings. divide at ranom index each of them.
"g/r / e/at" --> "r/g / e/at" // random decision was to swap the first substring and to keep the second substring in the same order.
"r/g / e/at" --> "r/g / e/ a/t" // again apply the algorithm recursively, divide "at" to "a/t".
"r/g / e/ a/t" --> "r/g / e/ a/t" // random decision is to keep both substrings in the same order.
The algorithm stops now and the result string is "rgeat" which is s2.
As there is one possible scenario that led s1 to be scrambled to s2, we return true.

Example 2:
Input: s1 = "abcde", s2 = "caebd"
Output: false

Example 3:
Input: s1 = "a", s2 = "a"
Output: true
 

Constraints:

s1.length == s2.length
1 <= s1.length <= 30
s1 and s2 consist of lower-case English letters.

  

解法:DP(动态规划)

1.确定【状态】:

  • 字符串s1的index:i
  • 字符串s2的index:j
  • 两字符串的长度:k

2.确定【选择】:

dp[i][j][k]:对s1[i~i+k-1]和s2[j~j+k-1],进行第q个位置分割:(q:1~k-1)

  • 任意位置切分能得到一个true,则可返回true。

对于其中一个切分q:得到pre和post,以下两个操作,任意为true即可。

  • 不交换pre和post
    • 那么:s1_pre VS s2_pre 要满足题意 && s1_post VS s2_post 要满足题意
      • s1[i~i+q-1] vs s2[j~j+q-1] && s1[i+q~k] vs s2[j+q~k]
      • dp[i][j][q]                      && dp[i+q][j+q][k-q] 
  • 交换pre和post
    • 那么:s1_pre VS s2_post 要满足题意 && s1_post VS s2_pre 要满足题意
      • s1[i~i+q-1] vs s2[j+k-q~k] && s1[i+q~k] vs s2[j~j+k-q-1]
      • dp[i][j+k-q][q]                 && dp[i+q][j][k-q] 

3. dp[i][j][k]的含义:

字符串s1[i~i+k-1]   VS   字符串s2[j~j+k-1]

这两个子串是符合题意的字符串。(S1可以通过题目所述变换得到S2)

4. 状态转移:

dp[i][j][k]=

for all q:1~k-1 : OR{

  • dp[i][j][q]                      && dp[i+q][j+q][k-q] 
  • dp[i][j+k-q][q]                 && dp[i+q][j][k-q] 
  • }

5. base case:

  • dp[i][j][1]= (s1[i]==s2[j]?true:false)

代码参考:

 1 class Solution {
 2 public:
 3     //dp[i][j][k]: strlen = k
 4     //            s1[i~i+k-1] vs s2[j~j+k-1]
 5     //            they are Scramble? True or False
 6     //opt: divide at q:(1~k-1) OR { case_1 or case_2 } (for all q)
 7     //case_1: not swap:
 8     //      s1_pre vs s2_pre (len:q)   && s1_post vs s2_post (len:k-q)
 9     //      s1[i~i+q-1] vs s2[j~j+q-1] && s1[i+q~k] vs s2[j+q~k]
10     //    ->dp[i][j][q]                && dp[i+q][j+q][k-q] 
11     //case_2: swap: divide pos:s1[q], s2[k-q]
12     //      s1_pre vs s2_post (len:q)  && s1_post vs s2_pre (len:k-q)
13     //      s1[i~i+q-1] vs s2[j+k-q~k] && s1[i+q~k] vs s2[j~j+k-q-1]
14     //    ->dp[i][j+k-q][q]                && dp[i+q][j][k-q] 
15     //base:
16     //dp[i][j][1] = (if s1[i]==s2[j] then true others false)
17     bool isScramble(string s1, string s2) {
18         int len = s1.length();
19         vector<vector<vector<bool>>> dp(len, 
20                                         vector<vector<bool>>(len,
21                                                              vector<bool>(len+1, false)));
22         for(int k=1; k<=len; k++) {
23             for(int i=0; i<=len-k; i++) {
24                 for(int j=0; j<=len-k; j++) {
25                     if(k==1) dp[i][j][k] = (s1[i]==s2[j]?true:false);
26                     else {
27                         for(int q=1; q<k && !dp[i][j][k]; q++) {
28                             dp[i][j][k] = (dp[i][j][q] && dp[i+q][j+q][k-q]) 
29                                 || (dp[i][j+k-q][q] && dp[i+q][j][k-q]);
30                         }
31                     }
32                 }
33             }
34         }
35         return dp[0][0][len];
36     }
37 };
原文地址:https://www.cnblogs.com/habibah-chang/p/14566968.html