LeetCode每日一题之“交错字符串”

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

示例 1:

输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出: true

示例 2:

输入: s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出: false

首先这道题我们需要理解什么是"交错",我把s1和s2中的字符串在s3中用不同颜色表示出来,马上豁然开朗
s1用红色标注,s2用黄色标注:

示例1(当然组合不止这一种情况):
在这里插入图片描述
我们发现在s3中可以依序找到完整的s1以及s2的部分。
因此输出结果是true
然而示例2并不能像这样成功找到拼出s3的s1以及s2部分。
因此输出结果是false

很多人的第一想法可能是利用双指针法去解决问题。
给s1以及s2分别设置两个指针,从头指向尾,按序判断它们的字母是否与s3中的字母相等,如果s3中的字母全部能依序找到s1以及s2中的归宿,那么输出结果是true,否则结果是false。

乍一看,这个思路很对,然而实际实现后发现,对于示例1,给出的答案是false
我分析了一下原因,发现双指针法对于处理这种有很多重复字母的情况表现并不好,它没有办法判断目前这个同时满足条件的字母到底属于s1还是s2,如果判断错误,就会导致之后的字母无法正确组合出想要的结果,进而给出错误答案。

所以我们要另辟蹊径,利用“动态规划”。
第一件事是判断字母长度 ,如果|s1|+|s2|≠|s3|那么返回false
(字母长度都不一样,怎么可能得出正确结果呢)

如果长度相等,我们可以进行下一步操作。
定义:f[i][j]表示 s1 的前 i 个字母和 s2 的前 j 个字母是否能组成 s3的前 i+j 个字母,是一个布尔类型变量。

同时f[i][j]的值取决于f[i-1][j]的值,如果 s1 的第 i 个字母与 s3 的第 i+j 个字母相等,可以得出等式:
f [ i ][ j ] = f [ i-1 ][ j ] and (s1 [ i-1 ]==s3 [ i+j-1 ])

同理,f[i][j]取决于f[i][j-1]的值,如果 s2 的第 j 个字母与 s3 的第 i+j 个字母相等,可以得出等式:
f [ i ][ j ] = f [ i ][ j-1 ] and (s2 [ j-1 ]==s3 [ i+j-1 ])

综上,我们可以得出f[i][j]的总关系式为:

f[i][j] =  {f[i-1][j] and (s1[i-1]==s3[i+j-1])} or {f[i][j-1] and (s2[j-1]==s3[i+j-1])}

我们还要设置边界条件:f [0][0] = true
现在就可以用代码去实现了!

public class answer5 {
    public boolean isInterleave(String s1, String s2, String s3){
        int a = s1.length();
        int b = s2.length();
        int c = s3.length();

        //f二维数组[]中的数表示前多少个字母
        //s1,s2最多分别为前a和前b个字母,因此f定义的大小分别为a+1和b+1
        boolean[][] f = new boolean[a+1][b+1];
        f[0][0] = true;//边界条件

        if(a+b != c) return  false;//字母长度不一样即可结束判断

        //开始迭代计算每种f的情况
        for (int i = 0;i<=a;i++){
            for(int j = 0;j<=b;j++){
                int p = i+j-1;//p代指s3中目前考虑到的最后一个字符所在位置
                if(i>0) f[i][j] = f[i-1][j] && (s1.charAt(i-1)==s3.charAt(p));
                if(j>0) f[i][j] = f[i][j] || (f[i][j-1] && (s2.charAt(j-1)==s3.charAt(p)));
                //j这行多一个判决条件f[i][j]是因为要考虑到上一行 i 中判决的结果
            }
        }
        return f[a][b];

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值