zoukankan      html  css  js  c++  java
  • leetcode每日一题(2020-07-18):97. 交错字符串

    题目描述:
    给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。

    今日学习:
    1.遇到字符串,多想想前缀和以及动规
    2.滚动数组优化:只和当前以及上一状态有关的可以进行空间优化

    题解:
    1.我想的稍微复杂一点的dp
    2.官方dp
    3.优化dp

    /**
     * @param {string} s1
     * @param {string} s2
     * @param {string} s3
     * @return {boolean}
     */
    //动规
    var isInterleave = function(s1, s2, s3) {
        let n1 = s1.length
        let n2 = s2.length
        let n3 = s3.length
        // 长度不对肯定是false
        if(n1 + n2 != n3) return false
        // dp[i][j]表示i - 1长度的s1 + j - 1长度的s2 == i + j - 2长度的s3
        const dp = new Array(n1 + 1)
        for(let i = 0; i <= n1; i++) {
            dp[i] = new Array(n2 + 1).fill(false)
        }
        // s1,s2都是空字符串的时候,因为判断过三者长度,所以true
        dp[0][0] = true
        // s1为空,判断s2有几位和s3匹配
        for(let j = 1; j <= n2; j++) {
            if(s2[j - 1] == s3[j - 1]) {
                dp[0][j] = true
            }else {
                break
            }
        }
        // s2为空,判断s1有几位和s3匹配
        for(let i = 1; i <= n1; i++) {
            if(s1[i - 1] == s3[i - 1]) {
                dp[i][0] = true
            }else {
                break
            }
        }
        // 三种情况:
        // 1.i - 2的s1加上j - 2的s2与i + j - 4的s3匹配,那么看新进来的s1[i - 1]和s2[j - 1]是否顺序组成s3[i + j - 2][i + j - 1]
        // 2.i - 1的s1加上j - 2的s2与i + j - 3的s3匹配,那么看新进来的s2[j - 1]是否与s3[i + j - 1]相等
        // 3.i - 2的s1加上j - 1的s2与i + j - 3的s3匹配,那么看新进来的s1[i - 1]是否与s3[i + j - 1]相等
        for(let i = 1; i <= n1; i++) {
            for(let j = 1; j <= n2; j++) {
                if(dp[i - 1][j - 1] == true) {
                    if(s1[i - 1] == s3[i + j - 2] && s2[j - 1] == s3[i + j - 1]) {
                        dp[i][j] = true
                    }
                }
                if(dp[i][j - 1] == true) {
                    if(s2[j - 1] == s3[i + j - 1]) {
                        dp[i][j] = true
                    }
                }
                if(dp[i - 1][j] == true) {
                    if(s1[i - 1] == s3[i + j - 1]) {
                        dp[i][j] = true
                    }
                }
            }
        }
        // 返回n1个s1和n2个s2是否顺序组成s3
        return dp[n1][n2]
    };
    //官方动规
    var isInterleave = function(s1, s2, s3) {
        // 定义状态:
        // dp[i][j] = boolean 表示,s1的前[0, i)个字符,s1的前[0, j)个字符,能够凑成s3的[0, i+j)
        // 往问题规模变小了想,假设s1/s2少一个字符,照样能拼接成s3,那么再加一个也是可以拼接成s3
        // 状态转移方程:
        // dp[i][j] = (dp[i-1][j] && s1[i-1] === s3[i+j-1]) || (dp[i][j-1] && s2[j-1] === s3[i+j-1])
        // 解释:(dp[i-1][j] && s1[i-1] === s3[i+j-1]),
        // dp[i-1][j] 意思是说s1少一个,但是s3的结尾是s1凑成的,s1再多一个也可也呀
        // dp[i][j-1] 同上;
        // base case:
        // 当s1为空的时候,dp[0][j] = (dp[0][j-1] && s2[j - 1] == s3[j - 1]) ? true : false
        // 当s2为空的时候,dp[i][0] = (dp[i-1][0] && s1[i - 1] == s3[i - 1]) ? true : false
        // dp[0][0] = true,
        // 边界,需要用到空串
        let n = s1.length;
        let m = s2.length;
        if (m + n != s3.length) {
            return false;
        }
        let dp = Array.from(Array(n + 1), () => Array(m + 1).fill(false));
        for (let i = 0; i <= n; i++) {
            for (let j = 0; j <= m; j++) {
                if(i == 0 && j == 0){
                    dp[i][j] = true
                }else if (i == 0) {
                    // s1 为空的情况
                    dp[i][j] = (dp[i][j - 1] && s2[j - 1] == s3[j - 1]) ? true : false;
                } else if (j == 0) {
                    // s2 为空的情况
                    dp[i][j] = (dp[i - 1][j] && s1[i - 1] == s3[i - 1]) ? true : false;
                } else {
                    dp[i][j] =
                        (dp[i - 1][j] && s1[i - 1] === s3[i + j - 1]) ||
                        (dp[i][j - 1] && s2[j - 1] === s3[i + j - 1]);
                }
            }
        }
        return dp[n][m];
    }
    //滚动数组优化
    var isInterleave = function(s1, s2, s3) {
        let n1 = s1.length;
        let n2 = s2.length;
        if (n1 + n2 != s3.length) {
            return false;
        }
        const dp = new Array(n2 + 1).fill(false)
        dp[0] = true
        for (let i = 0; i <= n1; i++) {
            for(let j = 0; j <= n2; j++) {
                let p = i + j - 1
                if(i > 0) {
                    dp[j] &= (s1[i - 1] == s3[p])
                }
                if(j > 0) {
                    dp[j] |= (dp[j - 1] && s2[j - 1] == s3[p])
                }
            }
        }
        return dp[n2]
    }
    
  • 相关阅读:
    关于java.lang.reflect.InvocationTargetException
    Java并发编程(三)后台线程(Daemon Thread)
    Lab 7-2
    Lab 7-1
    Lab 6-3
    Lab 6-2
    Lab 6-1
    Lab 5-1
    Lab 3-4
    Lab 3-3
  • 原文地址:https://www.cnblogs.com/autumn-starrysky/p/13334896.html
Copyright © 2011-2022 走看看