leetcode-97. Interleaved string

Keywords: Algorithm leetcode Dynamic Programming

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

Posted by devil6600 on Sat, 04 Dec 2021 15:28:37 -0800