【Lintcode】29. Interleaving String

题目地址:

https://www.lintcode.com/problem/interleaving-string/description

给定三个字符串 s 1 s_1 s1 s 2 s_2 s2 s 3 s_3 s3,问 s 1 s_1 s1 s 2 s_2 s2是否可以”交织“在一起得到 s 3 s_3 s3。交织的意思是,保持 s 1 s_1 s1 s 2 s_2 s2里面字符相对顺序不变的情况下,将它们的字符拆开然后重新组合在一起,能否得到 s 3 s_3 s3

思路是动态规划。设 f [ i ] [ j ] f[i][j] f[i][j]表示 s 1 s_1 s1的前 i i i个字符和 s 2 s_2 s2的前 j j j个字符交织在一起是否可以得到 s 3 s_3 s3的前 i + j i+j i+j个字符。这里的 i i i j j j都从 1 1 1开始计数,前 0 0 0个字符视为空串。

很显然, f [ 0 ] [ 0 ] = t r u e f[0][0]=true f[0][0]=true。接下来,
如果 s 1 [ i − 1 ] = s 3 [ i + j − 1 ] s_1[i-1]=s_3[i+j-1] s1[i1]=s3[i+j1],那么如果 f [ i − 1 ] [ j ] = t r u e f[i-1][j]=true f[i1][j]=true的话 f [ i ] [ j ] f[i][j] f[i][j]就等于 t r u e true true
如果 s 2 [ j − 1 ] = s 3 [ i + j − 1 ] s_2[j-1]=s_3[i+j-1] s2[j1]=s3[i+j1],那么如果 f [ i ] [ j − 1 ] = t r u e f[i][j-1]=true f[i][j1]=true的话 f [ i ] [ j ] f[i][j] f[i][j]就等于 t r u e true true
如果 s 1 [ i − 1 ] = s 3 [ i + j − 1 ] s_1[i-1]=s_3[i+j-1] s1[i1]=s3[i+j1] s 2 [ j − 1 ] = s 3 [ i + j − 1 ] s_2[j-1]=s_3[i+j-1] s2[j1]=s3[i+j1]都不成立, f [ i ] [ j ] = f a l s e f[i][j]=false f[i][j]=false

代码如下:

public class Solution {
    /**
     * @param s1: A string
     * @param s2: A string
     * @param s3: A string
     * @return: Determine whether s3 is formed by interleaving of s1 and s2
     */
    public boolean isInterleave(String s1, String s2, String s3) {
        // write your code here
        // 如果字符串的长度不符合要求则直接返回false
        if (s1.length() + s2.length() != s3.length()) {
            return false;
        }
        
        int l1 = s1.length(), l2 = s2.length();
        boolean[][] dp = new boolean[l1 + 1][l2 + 1];
        
        for (int i = 0; i <= l1; i++) {
            for (int j = 0; j <= l2; j++) {
                if (i == 0 && j == 0) {
                    dp[i][j] = true;
                } else {
                	// 先初始化dp[i][j]为false,接下来根据两种可能性尝试去更新它
                    dp[i][j] = false;
                    if (i > 0 && s1.charAt(i - 1) == s3.charAt(i + j - 1)) {
                        dp[i][j] |= dp[i - 1][j];
                    }
                    if (j > 0 && s2.charAt(j - 1) == s3.charAt(i + j - 1)) {
                        dp[i][j] |= dp[i][j - 1];
                    }
                }
            }
        }
        
        return dp[l1][l2];
    }
}

时空复杂度 O ( m n ) O(mn) O(mn) m m m n n n分别是 s 1 s1 s1 s 2 s2 s2的长度。

可以使用空间优化的方式使得空间复杂度降为 O ( n ) O(n) O(n)。我们注意到, f [ i ] [ j ] f[i][j] f[i][j]只取决于其正上方和正左方的数据,所以我们更新的时候 j j j需要从小到大更新,保证依赖正左方的数据的时候左方数据已经被更新。代码如下:

public class Solution {
    /**
     * @param s1: A string
     * @param s2: A string
     * @param s3: A string
     * @return: Determine whether s3 is formed by interleaving of s1 and s2
     */
    public boolean isInterleave(String s1, String s2, String s3) {
        // write your code here
        if (s1.length() + s2.length() != s3.length()) {
            return false;
        }
        
        int l1 = s1.length(), l2 = s2.length();
        boolean[] dp = new boolean[l2 + 1];
        
        for (int i = 0; i <= l1; i++) {
            for (int j = 0; j <= l2; j++) {
                if (i == 0 && j == 0) {
                    dp[0] = true;
                } else {
                	// 原先的逻辑是,先初始化dp[i][j]为false,然后逐次尝试更新它
                	// 转变为一维后,逻辑变为,第一个if的条件如果成立,dp[j]不变,否则dp[j]赋值为false,接下来再根据第二个if进行更新。
                	// 这里不能一上来就把dp[j]初始化为false,因为我们需要用到上一行的dp[j]的值,所以必须要先用掉这个信息。
                    if (!(i > 0 && s1.charAt(i - 1) == s3.charAt(i + j - 1))) {
                        dp[j] = false;
                    }
                    if (j > 0 && s2.charAt(j - 1) == s3.charAt(i + j - 1)) {
                        dp[j] |= dp[j - 1];
                    }
                }
            }
        }
        
        return dp[l2];
    }
}

时间复杂度不变,空间 O ( n ) O(n) O(n)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值