Leetcode 97. 交错字符串

题目

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

示例 1:

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

示例 2:

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

解答

解法一:递归

代码很容易理解。

主要思想是:s3 当前位置的字符要么来自 s1 , 要么来自 s2 。

递归代码有很多重复运算,必然会导致超时 TLE 。

代码
class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        if(s3.length() != s1.length() + s2.length()) return false;
        if(s3.isEmpty()) return true;
        
        char first = s3.charAt(0);
        if(!s1.isEmpty() && first == s1.charAt(0)) {
            if(isInterleave(s1.substring(1), s2, s3.substring(1))) return true;
        }
        
        if(!s2.isEmpty() && first == s2.charAt(0)) {
            if(isInterleave(s1, s2.substring(1), s3.substring(1))) return true;
        }
        
        return false;
    }
}
结果

在这里插入图片描述

使用记忆化搜索可以去掉大量重复的计算。

记忆化搜索代码
class Solution {
    
    // memo[i][j] 表示:s3[0 .. i + j - 1] 是否 s1[0 ... i - 1] 与 s2[0 ... j - 1] 的交错串
    private Boolean[][] memo;
    public boolean isInterleave(String s1, String s2, String s3) {
        memo = new Boolean[s1.length() + 1][s2.length() + 1];
        return isInterleave(s1.toCharArray(), s1.length(), s2.toCharArray(), s2.length(), s3.toCharArray(), s3.length());
    }
    
    private boolean isInterleave(char[] w1, int i, char[] w2, int j, char[] w3, int k) {
        if(memo[i][j] != null) return memo[i][j];
        
        boolean ret = false;
        if(k != i + j) {
            ret = false;
        } else if(k == 0) {
            ret = true;
        } else {
            if(i != 0 && w1[i - 1] == w3[k - 1] && isInterleave(w1, i - 1, w2, j, w3, k - 1)) ret = true;
            if(j != 0 && w2[j - 1] == w3[k - 1] && isInterleave(w1, i, w2, j - 1, w3, k - 1)) ret = true;
        }
        
        memo[i][j] = ret;
        return ret;
    }
}
结果

在这里插入图片描述

解法二:动态规划

动态规划四要素:

  1. 状态定义:dp[i][j] 表示 s1[0 … i - 1] 与 s2[0 … j - 1] 是否能形成交错字符串 s3[0 … i + j - 1]。

  2. 状态转移:dp[i][j] = (dp[i - 1][j] && s1 与 s3 当前字符是否匹配) || (dp[i][j - 1] && s2 与 s3 当前字符是否匹配);

  3. 状态初始化:dp[0][0] = true 。

  4. 结果:dp[s1.length()][s2.length()]

复杂度:O(nm) 时间,O(nm) 空间。(tips:空间可以优化)

代码
public class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        if (s3.length() != s1.length() + s2.length()) return false;
        
        boolean dp[][] = new boolean[s1.length() + 1][s2.length() + 1];
        for (int i = 0; i <= s1.length(); i ++) {
            for (int j = 0; j <= s2.length(); j ++) {
                if (i == 0 && j == 0) {
                    dp[i][j] = true;
                } else if (i == 0) {
                    dp[i][j] = dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1);
                } else if (j == 0) {
                    dp[i][j] = dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1);
                } else {
                    dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) 
                        || (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1));
                }
            }
        }
        
        return dp[s1.length()][s2.length()];
    }
}

结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值