leetcode每日一题(2020-07-18):97. 交错字符串

摘要:
题目描述:给定三个字符串s1,s2,s3,验证s3是否是由s1和s2交错组成的。今日学习:1.遇到字符串,多想想前缀和以及动规2.滚动数组优化:只和当前以及上一状态有关的可以进行空间优化题解:1.我想的稍微复杂一点的dp2.官方dp3.优化dp/***@param{string}s1*@param{string}s2*@param{string}s3*@return{boolean}*///动规varisInterleave=function{letn1=s1.lengthletn2=s2.lengthletn3=s3.length//长度不对肯定是falseif(n1+n2!true:false//当s2为空的时候,dp[i][0]=?true:false//dp[0][0]=true,//边界,需要用到空串letn=s1.length;letm=s2.length;if(m+n!true:false;}else{dp[i][j]=||;}}}returndp[n][m];}//滚动数组优化varisInterleave=function{letn1=s1.length;letn2=s2.length;if(n1+n2!

题目描述:
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。
leetcode每日一题(2020-07-18):97. 交错字符串第1张

今日学习:
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]
}

免责声明:文章转载自《leetcode每日一题(2020-07-18):97. 交错字符串》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇jQuery .tmpl(), .template()学习资料小结伪表和伪列下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【DP】洛谷 P1854 花店橱窗布置

你们好啊,我又回来了。P1854这是一道动态规划题。 还是先放题目,防止走错》》》 这次先放数据,上次就忘了.......... 其实我们看见数据只有100,其实就可以考虑瞎搞,什么记忆化搜索,题解还有人求最长路,闲的无聊你可以自己尝试。 我这里介绍一下这题正解 -> dp。 其实很显然的吧........ 这个题,我们考虑我们考虑用f[i][j...

BZOJ 1296 粉刷匠(分组背包套DP)

刚开始往网络流的方向想。建不出图。。。 因为每次只能对一行进行染色。每一行都是独立的。 对于每一行,因为格子只能染一次,所以可以发现这是一个多阶段决策问题,这个决策就是当前格子染0还是染1. 令dp[i][j][k](k==0||k==1)表示当前行第i个格子用了j次染色,且这次染色染为k色 的最多有效格子。 这样我们用了O(n*m*m)得出了每一行用了v...

Android 一种非常好用的Android屏幕适配

前言 网上关于屏幕适配的文章已经铺天盖地了,为什么我还要讲?因为网上现在基本都是使用px适配,即每种屏幕分辨率的设备需要定义一套dimens.xml文件。再加上有些手机还有虚拟按键(例如华为),这样就还需要每个有虚拟按键的设备加多一套dimens.xml文件,再加上平板那些你会发现dimens.xml文件所占的体积已经超过2M了!这绝对不是我们想要的。...

AmazonS3-Java对接

AmazonS3-Java对接 1、Amazons3? S3 是一个全球存储区域网络(SAN),它表现为一个超大的硬盘,可以存储AWS用户上传的资源文件。S3可根据AWS用户需求不同创建不同区域、不同名称的Bucket(桶),代码调用的时候可直接根据BucketNamed对Bucket进行访问(前提是AWS凭证认证通过)。 2、基础配置 1、AWS用户凭证...

bzoj:1072: [SCOI2007]排列perm

Description   给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0)。例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种。 Input   输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开。s保证只包含数字0, 1, 2, 3, 4, 5, 6, 7, 8,...

[转载]字符串-02. 删除字符串中的子串(20)

输入2个字符串S1和S2,要求删除字符串S1中出现的所有子串S2,即结果字符串中不能包含S2。 输入格式: 输入在2行中分别给出不超过80个字符长度的、以回车结束的2个非空字符串,对应S1和S2。 输出格式: 在一行中输出删除字符串S1中出现的所有子串S2后的结果字符串。 输入样例: Tomcat is a male ccatat cat 输出样例: T...