交错字符串 - 动态规划

题目描述

链接:https://leetcode-cn.com/problems/interleaving-string
给定三个字符串 s1, s2, s3, 验证 s3 是否是由 s1 和 s2 交错组成的。

示例 1:

输入: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出: true
示例 2:

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

题目分析

这个题目是一道动态规划求解的题.

首先, 分析题干, 先得知道什么是 交错的含义. 就是保持相对位置不变, 交错组合.

说到动态规划, 我们就得分析几个问题:

  1. dp数组的含义
  2. 边界值
  3. 状态转移

按照这 “三步走”, 就能快速解决掉动态规划的问题.

  • dp数组的含义:

    定义dp[i] [j]为 由i个s1前缀与j个s2前缀是否能交错出i+j个前缀的s3.

  • 边界值:

    dp[0] [0] = true

    dp[0] [1 ~ len1], 如果对位相等, 就true, 否则只要有一位不匹配, 直接false

    dp[1 ~ len2] [0] 如果对位相等, 就true, 否则只要有一位不匹配, 直接false.

    // 初始化边界
    dp[0][0] = true;
    // 利用flag判断是否有过false
    boolean flag = true;
    for (int i = 0; i < len1; i++) {
        if (str1[i] != str3[i]) {
            flag = false;
        }
        dp[i+1][0] = flag;
    }
    flag = true;
    for (int i = 0; i < len2; i++) {
        if (str2[i] != str3[i]) {
            flag = false;
        }
        dp[0][i+1] = flag;
    }
    
  • 状态转移

    // 状态转移
    for (int i = 1; i <= len1; i++) {
        for (int j = 1; j <= len2; j++) {
            // 假设这个字符来自于str1, 判断这个字符之前一段是否能拼出来
            if (str1[i - 1] == str3[i+j - 1] && dp[i-1][j] == true) dp[i][j] = true;
            // 假设这个字符来自于str2, 判断这个字符之前一段是否能拼出来
            else if (str2[j - 1] == str3[i+j - 1] && dp[i][j-1] == true) dp[i][j] = true;
            else dp[i][j] = false;
        }
    }
    

代码

class Solution {
    public boolean isInterleave(String s1, String s2, String s3) {
        if (s3.length() != s1.length() + s2.length()) return false;
        if (s1.length() == 0 || s2.length() == 0 || s3.length() == 0) {
            String t = s1 + s2;
            return t.equals(s3);
        }
        // 定义dp[i][j]为 用字符串s1[0~i-1] 和 字符串s2[0~j-1] 能否拼成 s3[i+j-1] 
        //也就是用i个s1, j个s2能否拼出i+j个前缀的s3.
        char[] str1 = s1.toCharArray();
        char[] str2 = s2.toCharArray();
        char[] str3 = s3.toCharArray();
        int len1 = str1.length, len2 = str2.length, len3 = str3.length;
        boolean[][] dp = new boolean[len1+1][len2+1];
        // 初始化边界
        dp[0][0] = true;
        boolean flag = true;
        for (int i = 0; i < len1; i++) {
            if (str1[i] != str3[i]) {
                flag = false;
            }
            dp[i+1][0] = flag;
        }
        flag = true;
        for (int i = 0; i < len2; i++) {
            if (str2[i] != str3[i]) {
                flag = false;
            }
            dp[0][i+1] = flag;
        }
        // 状态转移
        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                // 假设这个字符来自于str1
                if (str1[i - 1] == str3[i+j - 1] && dp[i-1][j] == true) dp[i][j] = true;
                // 假设这个字符来自于str2
                else if (str2[j - 1] == str3[i+j - 1] && dp[i][j-1] == true) dp[i][j] = true;
                else dp[i][j] = false;
            }
        }
        return dp[len1][len2];
    }
}

你可能感兴趣的:(面试算法题目)