subject
Link: https://leetcode-cn.com/problems/interleaving-string
Given the three strings s1, s2 and s3, please help verify whether s3 is composed of s1 and s2 interleaving.
The definition and process of interleaving two strings s and t are as follows, in which each string will be divided into several non empty substrings:
s = s1 + s2 + ... + sn
t = t1 + t2 + ... + tm
|n - m| <= 1
Interleaving is s1 + t1 + s2 + t2 + s3 + t3 +... Or t1 + s1 + t2 + s2 + t3 + s3 +
Tip: a + b means that the strings a and b are connected.
Example 1:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcac"
Output: true
Example 2:
Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
Output: false
Example 3:
Input: s1 = "", s2 = "", s3 = ""
Output: true
Problem solving idea I
Each time, compare whether the first character of s1/s2 is equal to s3. If it is equal, continue to recursively compare the subsequent strings.
There are four cases:
- If the first character of s1 and s3 is equal, continue to compare the removal of the first character of s1 and s3.
- If the first character of s2 and s3 is equal, continue to compare the removal of the first character of s2 and s3.
- If both s1/s2 and s3 are equal to the first character of s3, continue to compare s2, s3 and the removal of the first character from s1 and s3.
- If s1 and s2 are not equal to s3, false is returned
Problem solving code
public boolean isInterleave(String s1, String s2, String s3) { // The length is not equal and does not pass directly if (s1.length() + s2.length() != s3.length()) { return false; } // If s2 is a null character, s1 must be equal to s3 if (Objects.equals(s2, "")) { return Objects.equals(s3, s1); } // If s1 is empty, s2 is equal to s3 if (Objects.equals(s1, "")) { return Objects.equals(s3, s2); } // Match the first character each time char s1Char = s1.charAt(0); char s2Char = s2.charAt(0); char s3Char = s3.charAt(0); if (s1Char != s3Char && s2Char != s3Char) { return false; } // If the first characters of s1 and s2 are satisfied, two situations need to be returned if (s1Char == s3Char && s2Char == s3Char) { return isInterleave(s1.substring(1), s2, s3.substring(1)) || isInterleave(s1, s2.substring(1), s3.substring(1)); } // The rest can be compared recursively if (s1Char == s3Char) { return isInterleave(s1.substring(1), s2, s3.substring(1)); } return isInterleave(s1, s2.substring(1), s3.substring(1)); }
Submit results
99 / 106 pass test cases, status: time limit exceeded
Optimize code
Since the comparison starts from the next character every time here, because the string is final, cutting the string will cause the need to create a new string object every time, resulting in a waste of some efficiency. In fact, the subscript to be compared can be updated every time, so it is not necessary to cut the string.
public boolean isInterleave(String s1, String s2, String s3) { // The length is not equal and does not pass directly if (s1.length() + s2.length() != s3.length()) { return false; } return isInterleaveDFS(s1, s2, s3, 0, 0, 0); } private boolean isInterleaveDFS(String s1, String s2, String s3, int s1Index, int s2Index, int s3Index) { // If s2 is a null character, s1 must be equal to s3 if (s2Index >= s2.length()) { return Objects.equals(s3.substring(s3Index), s1.substring(s1Index)); } // If s1 is empty, s2 is equal to s3 if (s1Index >= s1.length()) { return Objects.equals(s3.substring(s3Index), s2.substring(s2Index)); } // Match the first character each time char s1Char = s1.charAt(s1Index); char s2Char = s2.charAt(s2Index); char s3Char = s3.charAt(s3Index); if (s1Char != s3Char && s2Char != s3Char) { return false; } // If the first characters of s1 and s2 are satisfied, two situations need to be returned if (s1Char == s3Char && s2Char == s3Char) { return isInterleaveDFS(s1, s2, s3, s1Index + 1, s2Index, s3Index + 1) || isInterleaveDFS(s1, s2, s3, s1Index, s2Index + 1, s3Index + 1); } // The rest can be compared recursively if (s1Char == s3Char) { return isInterleaveDFS(s1, s2, s3, s1Index + 1, s2Index, s3Index + 1); } return isInterleaveDFS(s1, s2, s3, s1Index, s2Index + 1, s3Index + 1); }
Submit results
105 / 106 pass test cases, status: time limit exceeded
So far, recursive de depth traversal can not deal with this problem. Instead, dynamic programming is used.
Problem solving idea 2
Here, each time the character of s1 or s2 is traversed to compare s3, it can be recorded as the result of whether the previous character can be converted into a part of s3 and whether the current character is equal to s3.
Therefore, dp[0] = true, DP [i] = DP [I-1] & & S3 = = S1 [I-1], and s2 is the same.
According to the subsequent character cross comparison, it can be converted into the following dp expression. In essence, the string comparison result is saved in dp[i][j], which respectively represents that the previous character is the i-1 character of s1 and the j-1 character of s2. Therefore, the final result return should be dp[i][j].
dp[i][j]=dp[i-1][j] && s1[i-1]===s3[i-1+j] || dp[i][j-1] && s2[j-1] == s3[i-1+j]
The code is as follows
public boolean isInterleave(String s1, String s2, String s3) { // The length is not equal and does not pass directly if (s1.length() + s2.length() != s3.length()) { return false; } boolean[][] dp = new boolean[s1.length() + 1][s2.length() + 1]; dp[0][0] = true; for (int i = 1; i <= s1.length(); i++) { dp[i][0] = dp[i - 1][0] && s3.charAt(i - 1) == s1.charAt(i - 1); } for (int i = 1; i <= s2.length(); i++) { dp[0][i] = dp[0][i - 1] && s3.charAt(i - 1) == s2.charAt(i - 1); } for (int i = 1; i <= s1.length(); i++) { for (int j = 1; j <= s2.length(); j++) { dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i - 1 + j)) || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i - 1 + j)); } } return dp[s1.length()][s2.length()]; }
Submit results
Execution result: execution time: 5 ms