Leetcode 97. Interleaving String

Leetcode 97. Interleaving String

Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.

Example 1:

Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
Output: true

Example 2:

Input: s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
Output: false

思路:

一开始选择使用递归的方法,一个字符串一个字符串的进行字符搜索,但发现会跳不出最后的条件并且会把栈给堆爆,所以就选择了借鉴一下dalao们的思路。

大致想法如下:

整体思路是:动态规划

那么要怎么规划呢?

我们可以把给定的字符串s1s2制作成一个布尔类型的二维地图(1表示可以通行,0表示不可通行),且初始化地图除了左上角的[0,0]对应的格子为1外(后面会解释),其余空格全为0,

例:

s1 = aas2 =ab

那么地图可以构建为:

0aa
0100
a000
b000
  • 地图第一行对应s1
  • 地图第二行对应s2

我们可以这么理解,如果存在这么一个由s1s2构成的字符串s3,那么就存在一条从左上角走到右下角的道路,这里我们举个例子:

假如:

s3 = aaba

那么我们可以这么走

  • [0,0] ->(往右走)
  • [0,a] (并将该格子置1,这一步匹配a) ->(往下走)
  • [a,a] (并将该格子置1,这一步匹配a) ->(往下走)
  • [b,a] (并将该格子置1,这一步匹配b) ->(往右走)
  • [b,a] (并将该格子置1,这一步匹配a)

至此也就完成了匹配过程:aaba

当所有的搜索完成时候,如果我们可以得到右下角的格子的布尔值为1,那么证明匹配完成,如果布尔值为0,则证明匹配不成立

还有一个问题就是:我们如何判断将某个格子置0还是置1呢?

方法如下:

这里假设i = s1.size , j = s2.size + 1, 地图为DP[i +1][j +1]

  • 由于两个空串可以直接完成匹配,所以DP[0][0] = 1 (这也就解释为什么最最上角的格子置为1了)

  • 对地图DP进行第一步赋值:

    • 当 j 等于0的时候,dp[i, 0]的值取决于dp[i-1, 0]是否为真以及s1[i-1]是否等于s3[i-1],即dp[i][0] = dp[i-1][0] && s1[i-1] == s3[i-1]

    • 同理,当 i 等于0的时候:

      dp[0][j] = dp[0][j-1] && s2[j-1] == s3[j-1]

  • 对地图进行除第一行或第一列外的格子进行赋值,递推公式为:dp[i, j] = (s1[i-1] == s3[i+j-1] && dp[i-1, j]) || (s2[j-1] == s3[i+j-1] && dp[i, j-1])。

    • 如果s1[i-1]与s3[i+j-1]相同,说明当前位置s1可以进行匹配,因此如果dp[i-1, j]也为真,dp[i, j]就为真。
    • 如果s2[j-1]与s3[i+j-1]相同,说明当前位置s2可以进行匹配,因此如果dp[i, j-1]也为真,dp[i, j]就为真。

在完成以上所有操作后,如果DP[i][j] == 1,那么可判断s3 为 s2 与 s1交叉构成。

代码:

class Solution
{
    public:
    bool isInterleave(string s1, string s2, string s3)
    {
        int l1 = s1.size(), l2 = s2.size(), l3 = s3.size();

        if(l3 != l1 + l2)
            return false;

        vector<vector<bool> > dp(l1 + 1, vector<bool>(l2 + 1, false));

        dp[0][0] = true;
        for(int i = 1; i <= l1; ++ i)
            dp[i][0] = dp[i - 1][0] && s1[i - 1] == s3[i - 1];
        for(int j = 1; j <= l2; ++ j)
            dp[0][j] = dp[0][j - 1] && s2[j - 1] == s3[j - 1];

        for(int i = 1; i <= l1; ++ i)
            for(int j = 1; j <= l2; ++ j)
                dp[i][j] = (s1[i - 1] == s3[i + j - 1] && dp[i - 1][j]) 
                || (s2[j - 1] == s3[i + j - 1] && dp[i][j - 1]);
        return dp[l1][l2];
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值