剑指offer96:字符串交织

题目:
给定三个字符串 s1、s2、s3,请判断 s3 能不能由 s1 和 s2 交织(交错) 组成。
两个字符串 s 和 t 交织 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:
s = s1 + s2 + … + sn
t = t1 + t2 + … + tm
|n - m| <= 1
交织 是 s1 + t1 + s2 + t2 + s3 + t3 + … 或者 t1 + s1 + t2 + s2 + t3 + s3 + …
提示:a + b 意味着字符串 a 和 b 连接。
在这里插入图片描述
示例一:输入:s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbcbcac”
输出:true
示例二:输入:s1 = “aabcc”, s2 = “dbbca”, s3 = “aadbbbaccc”
输出:false
示例三:输入:s1 = “”, s2 = “”, s3 = “”
输出:true
分析:
每步从字符串s1或s2中选出一个字符交织生产字符串s3中的一个字符,那么交织生成的字符串s3中的所有字符需要多少步骤,每一步即可能从字符串s1中选择一个字符也可能从字符串s2中选择一个字符,也就是说每步可能面临两个选择。该问题并没有要求列出所有字符串s1和s2交织得到字符串s3的方法,而只是判断能否将字符串s1和s2交织得到字符串s3,只是判断该问题的解是否存在,因而采用动态规划解决该问题。
确定状态转移方程:如果第一个字符串的最后一个字母和合成字符串最后的字母相同,则f(i,j)=f(i-1,j),如果第二个字符串的最后一个字母和合成字符串最后的字母相同,则f(i,j)=f(i,j-1)。-1代表空串

在这里插入图片描述

在这里插入图片描述

代码:

public class IsInterleave {
    
    
    public static void main(String[] args) {
    
    
        String s1 = "aabcc";
        String s2 = "dbbca";
        String s3 = "aadbbcbcac";
        IsInterleave isInterleave = new IsInterleave();
        boolean interleave2 = isInterleave.isInterleave2(s1, s2, s3);
        System.out.println(interleave2);
    }
    public boolean isInterleave1(String s1, String s2, String s3) {
    
    
        if (s1.length() + s2.length() != s3.length()){
    
    
            return false;
        }
        boolean[][] dp = new boolean[s1.length()+1][s3.length()+1];
        dp[0][0] = true;
        for (int i = 0; i < s1.length(); i++) {
    
    
            dp[i+1][0] = s1.charAt(i) == s3.charAt(i)&&dp[i][0];
        }
        for (int i = 0; i < s2.length(); i++) {
    
    
            dp[0][i+1] = s2.charAt(i) == s3.charAt(i)&&dp[0][i];
        }
        for (int i = 0; i < s1.length(); i++) {
    
    
            for (int j = 0; j < s2.length(); j++) {
    
    
                char ch1 = s1.charAt(i);
                char ch2 = s2.charAt(j);
                char ch3 = s3.charAt(i+j+1);
                dp[i+1][j+1] = (ch1 == ch3 && dp[i][j+1]) || (ch2 == ch3 && dp[i+1][j]);
            }
        }
        return dp[s1.length()][s2.length()];
    }
//    优化空间效率
    public boolean isInterleave2(String s1, String s2, String s3){
    
    
        if (s1.length() + s2.length() != s3.length()){
    
    
            return false;
        }
        boolean[][] dp = new boolean[2][s3.length()+1];
        dp[0][0] = true;
        for (int i = 0; i < s2.length(); i++) {
    
    
            dp[0][i+1] = s2.charAt(i) == s3.charAt(i)&&dp[0][i];
        }
        for (int i = 0; i < s1.length(); i++) {
    
    
            dp[(i+1)%2][0] = s1.charAt(i) == s3.charAt(i)&&dp[i%2][0];
            for (int j = 0; j < s2.length(); j++) {
    
    
                char ch1 = s1.charAt(i);
                char ch2 = s2.charAt(j);
                char ch3 = s3.charAt(i+j+1);
                dp[(i+1)%2][j+1] = (ch1 == ch3 && dp[i%2][j+1]) || (ch2 == ch3 && dp[(i+1)%2][j]);
            }
        }
        return dp[s1.length()%2][s2.length()];
    }
//    接着优化空间效率
    public boolean isInterleave3(String s1, String s2, String s3){
    
    
        if (s1.length() + s2.length() != s3.length()){
    
    
            return false;
        }
        if (s1.length() < s2.length()){
    
    
            return isInterleave3(s2,s1,s3);
        }
        boolean[] dp = new boolean[s2.length() + 1];
        dp[0] = true;
//        相当于二维数组第一行
        for (int j = 0; j < s2.length(); j++) {
    
    
            dp[j+1] = s2.charAt(j) == s3.charAt(j)&&dp[j];
        }
        for (int i = 0; i < s1.length(); i++) {
    
    
//            相当于逐个判断二维数组第一列是true还是false
            dp[0] = dp[0] && s1.charAt(i) == s3.charAt(i);
            for (int j = 0; j < s2.length(); j++) {
    
    
                char ch1 = s1.charAt(i);
                char ch2 = s2.charAt(j);
                char ch3 = s3.charAt(i+j+1);
                dp[j+1] = (ch1 == ch3 && dp[j+1]) || (ch2 == ch3 &&dp[j]);
            }
        }
        return dp[s2.length()];
    }
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Jiaodaqiaobiluo/article/details/123156290