87. Scramble String Hard

@problem@discussion
#String#Dynamic Programming



1/**
2 * [87] Scramble String
3 *
4 * We can scramble a string s to get a string t using the following algorithm:
5 * <ol>
6 * If the length of the string is 1, stop.
7 * If the length of the string is > 1, do the following:
8 *
9 * Split the string into two non-empty substrings at a random index, i.e., if the string is s, divide it to x and y where s = x + y.
10 * Randomly decide to swap the two substrings or to keep them in the same order. i.e., after this step, s may become s = x + y or s = y + x.
11 * Apply step 1 recursively on each of the two substrings x and y.
12 *
13 *
14 * </ol>
15 * Given two strings s1 and s2 of the same length, return true if s2 is a scrambled string of s1, otherwise, return false.
16 *  
17 * Example 1:
18 *
19 * Input: s1 = "great", s2 = "rgeat"
20 * Output: true
21 * Explanation: One possible scenario applied on s1 is:
22 * "great" --> "gr/eat" // divide at random index.
23 * "gr/eat" --> "gr/eat" // random decision is not to swap the two substrings and keep them in order.
24 * "gr/eat" --> "g/r / e/at" // apply the same algorithm recursively on both substrings. divide at random index each of them.
25 * "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.
26 * "r/g / e/at" --> "r/g / e/ a/t" // again apply the algorithm recursively, divide "at" to "a/t".
27 * "r/g / e/ a/t" --> "r/g / e/ a/t" // random decision is to keep both substrings in the same order.
28 * The algorithm stops now, and the result string is "rgeat" which is s2.
29 * As one possible scenario led s1 to be scrambled to s2, we return true.
30 *
31 * Example 2:
32 *
33 * Input: s1 = "abcde", s2 = "caebd"
34 * Output: false
35 *
36 * Example 3:
37 *
38 * Input: s1 = "a", s2 = "a"
39 * Output: true
40 *
41 *  
42 * Constraints:
43 *
44 * s1.length == s2.length
45 * 1 <= s1.length <= 30
46 * s1 and s2 consist of lowercase English letters.
47 *
48 */
49pub struct Solution {}
50
51// problem: https://leetcode.com/problems/scramble-string/
52// discuss: https://leetcode.com/problems/scramble-string/discuss/?currentPage=1&orderBy=most_votes&query=
53
54// submission codes start here
55use std::collections::HashMap;
56
57impl Solution {
58    pub fn is_scramble(s1: String, s2: String) -> bool {
59        let mut mem = HashMap::new();
60        return Self::_is_scramble(&s1, &s2, &mut mem);
61    }
62
63    fn _is_scramble<'a>(
64        s1: &'a str,
65        s2: &'a str,
66        map: &mut HashMap<(&'a str, &'a str), bool>,
67    ) -> bool {
68        if let Some(x) = map.get(&(s1, s2)) {
69            return *x;
70        }
71
72        if s1.len() != s2.len() {
73            map.insert((s1, s2), false);
74            return false;
75        }
76
77        if s1 == s2 {
78            map.insert((s1, s2), true);
79            return true;
80        }
81
82        let mut chs = vec![0; 26];
83        for c in s1.chars() {
84            chs[c as usize - 'a' as usize] += 1;
85        }
86        for c in s2.chars() {
87            chs[c as usize - 'a' as usize] -= 1;
88        }
89        for c in chs.iter() {
90            if *c != 0 {
91                map.insert((s1, s2), false);
92                return false;
93            }
94        }
95        for i in 1..s1.len() {
96            if Self::_is_scramble(&s1[..i], &s2[..i], map)
97                && Self::_is_scramble(&s1[i..], &s2[i..], map)
98            {
99                map.insert((s1, s2), true);
100                return true;
101            }
102            if Self::_is_scramble(&s1[..i], &s2[s2.len() - i..], map)
103                && Self::_is_scramble(&s1[i..], &s2[..s2.len() - i], map)
104            {
105                map.insert((s1, s2), true);
106                return true;
107            }
108        }
109        map.insert((s1, s2), false);
110        false
111    }
112}
113
114// submission codes end
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn test_87() {
122        assert_eq!(
123            Solution::is_scramble("great".to_owned(), "rgeat".to_owned()),
124            true
125        );
126        assert_eq!(
127            Solution::is_scramble("abcde".to_owned(), "caebd".to_owned()),
128            false
129        );
130        assert_eq!(
131            Solution::is_scramble("abb".to_owned(), "bba".to_owned()),
132            true
133        );
134    }
135
136    #[test]
137    fn test_87_2() {
138        assert_eq!(
139            Solution::is_scramble(
140                "eebaacbcbcadaaedceaaacadccd".to_owned(),
141                "eadcaacabaddaceacbceaabeccd".to_owned()
142            ),
143            false
144        );
145    }
146}
147


Back
© 2025 bowen.ge All Rights Reserved.