LeetCode097——交错字符串

我的LeetCode代码仓:https://github.com/617076674/LeetCode

原题链接:https://leetcode-cn.com/problems/interleaving-string/description/

题目描述:

知识点:动态规划、递归

思路一:递归实现(在LeetCode中提交会超时)

本题的思路其实很清晰,就是依次删去s3中在s1中出现的字符。

需要注意的是,删是按顺序地删。即对于s1 = "ab",s2 = "bc",s3 = "bbac"的情况,如果不考虑s1中"a"和"b"的相对位置,那么其结果就变成了true。而这个例子的结果明显是false。我们在删除的"b"的时候,应该从s3中被删除掉的"a"的那个位置之后去寻找"b",这样删除的"ab"才是真正的s1,不会对这种情形进行误判。因此,在递归的时候,我们需要传入一个额外的参数index,它记录的是上一次删除的字符的位置。我们下一个删除的字符在s3中的位置必须大于等于index值。

递归终止条件

(1)如果s1加上s2的长度和s3的长度不相等,即返回false。

(2)如果s1的长度为0,比较字符串s2是否与字符串s3相等,相等则返回true,不相等则返回false。

递归过程

(1)从s3中index位置开始寻找与s1中第一个字符相同的字符,用一个ArrayList<Integer>型变量arrayList记录其位置。

(2)对于arrayList中的每一个位置,我们都尝试删除,并递归调用该函数来判断是否s3删除对应字符后的字符串是否右s1中除了第一个字符外的子串和s2交错组成。只要有任何一个位置返回的结果是true,就直接返回true。否则,返回false。

时间复杂度是O(n * m),其中n为字符串s1的长度,m为字符串s3的长度。空间复杂度即递归深度,是O(n)。

JAVA代码:

public class Solution {

    public boolean isInterleave(String s1, String s2, String s3) {
        return isInterleave(s1, s2, s3, 0);
    }

    private boolean isInterleave(String s1, String s2, String s3, int index){
        int n1 = s1.length();
        int n2 = s2.length();
        int n3 = s3.length();
        if(n1 + n2 != n3){
            return false;
        }
        if(s1.length() == 0){
            return s2.equals(s3);
        }

        ArrayList<Integer> arrayList = new ArrayList<>();
        for(int i = index; i < n3; i++){
            if(s1.charAt(0) == s3.charAt(i)){
                arrayList.add(i);
            }
        }
        for (int i = 0; i < arrayList.size(); i++) {
            if(isInterleave(s1.substring(1), s2, s3.substring(0, arrayList.get(i)) + s3.substring(arrayList.get(i) + 1), arrayList.get(i))){
                return true;
            }
        }
        return false;
    }
}

思路二:动态规划

状态定义

f(x, y) -------- s1中[0, x - 1]区间的子串和s2中[0, y - 1]区间的子串能否构成s3中[0, x + y - 1]区间的子串。

状态转移

(1)当x == 0时,说明此时s1中[0, x - 1]区间的子串是一个空串。只需根据s2中[0, y - 1]区间的子串和s3中[0, y - 1]区间的子串判断即可。

(2)当y == 0时,说明此时s2中[0, y - 1]区间的子串是一个空串。只需根据s1中[0, x - 1]区间的子串和s3中[0, x - 1]区间的子串判断即可。

(3)当x != 0且y != 0时,分为两种情况

a:如果f(x - 1, y) == true,即s1中[0, x - 2]区间的子串能够和s2中[0, y - 1]区间的子串构成s3中[0, x + y - 2]区间的子串且s1.charAt(x - 1) == s3.charAt(x + y - 1),显然f(x, y)值为true。

b:如果f(x, y - 1) == true,即s1中[0, x - 1]区间的子串能够和s2中[0, y - 2]区间的子串构成s3中[0, x + y - 2]区间的子串且s2.charAt(y - 1) == s3.charAt(x + y - 1),显然f(x, y)值为true。

时间复杂度和空间复杂度均是O(n * m),其中n为字符串s1的长度,m为字符串s2的长度。

JAVA代码:

public class Solution {

    public boolean isInterleave(String s1, String s2, String s3) {
        int n1 = s1.length();
        int n2 = s2.length();
        int n3 = s3.length();
        if(n1 + n2 != n3){
            return false;
        }
        boolean[][] flags = new boolean[n1 + 1][n2 + 1];
        flags[0][0] = true;
        for (int i = 1; i < n1 + 1; i++) {
            if(!flags[i - 1][0] || s1.charAt(i - 1) != s3.charAt(i - 1)){
                break;
            }
            flags[i][0] = true;
        }
        for(int i = 1; i < n2 + 1; i++){
            if(!flags[0][i - 1] || s2.charAt(i - 1) != s3.charAt(i - 1)){
                break;
            }
            flags[0][i] = true;
        }
        for (int i = 1; i < n1 + 1; i++) {
            for (int j = 1; j < n2 + 1; j++) {
                if(flags[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)){
                    flags[i][j] = true;
                    continue;
                }
                if(flags[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1)){
                    flags[i][j] = true;
                }
            }
        }
        return flags[n1][n2];
    }
}

LeetCode解题报告:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值