leecode97:交错字符串

题目描述:

给定三个字符串 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交错,明显不是这道题的目的,而且时间肯定会超时,所以直接看了官方解答。

DP动态规划
  • 定义数组f(i, j)s1的前i个字符和s2的前j个字符能否交错组成s3的前i+j个元素。C++里非0的都为true,0为false。
  • 能交错的话证明s3里的元素是来自s1和s2,分两种情况:
  1. s1的第i个元素和s3的第i+j个元素相等:
    s1的前i个元素和s2的前j个元素能否交错组成s3的前i+j个元素,取决于s1的前i-1个元素和s2的前j个元素能否交错组成s3的前i-1+j个元素。
    此时f(i,j)的真假取决于f(i-1,j)
  2. s2的第j个元素和s3的第i+j个元素相等:
    s2的前j个元素和s1的前i个元素能否交错组成s3的前i+j个元素,取决于s2的前j-1个元素和s1的前i个元素能否交错组成s3的前i+j-1个元素。
    此时f(i,j)的真假取决于f(i,j-1)

得到动态规划DP的核心方程为:
注意不要搞混:这里的f(i-1,j)中的i-1和j指的是前i-1和前j个元素;
s1(i-1)==s3(p)里的i-1与p指的就是第i和第p=i+j个元素(因为数组的话下标是从0开始的);

//DP = 
p=i+j;
f(i, j) = (f(i-1,j) && s1(i-1)==s3(p)) || (f(i,j-1) && s2(j-1)==s3(p));
代码1:
class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) 
    {
    	//定以长度以及结果(类似于布尔数组吧,false就是0,非0就是true)
    	int m = s1.size(), n = s2.size(), t = s3.size();
    	auto f = vector<vector<int>> (m+1, vector<int>(n+1, false));//auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型
    	//特殊处理
    	if(m+n != t)
			retuen false;
		//处理
		f[0][0] = true;
		for(int i=0;i<m+1;i++)
		{
			for(int j=0;j<n+1;j++)
			{
				int p = i+j-1;
				if(i>0)//包含了j=0的情况
				{
					f[i][j] |= (f[i-1][j] && (s1[i-1]==s3[p]));
				}
				if(j>0)//包含了i=0的情况
				{
					f[i][j] |= (f[i][j-1] && (s2[j-1]==s3[p]));
				} 
			}
		}
		return f[m][n];
    }
};

定义二维数组的方法二:

vector<vector<int>> f(m+1);
for(int i=0;i<m+1;i++)
{
	f[i] = vector<int> (n+1, i);
}
代码2(动态规划路径问题解法):

问题:有点不懂为何要设置这个边界
关于这个边界值:有边界值才能有与的条件,类似于代码1。
在这里插入图片描述

下表从1开始是因为:f[i,j]表示s1前i字符能与s2前j字符组成s3前i+j个字符

思路分析:
边界1:路径左上角的值f[0][0]=true;
边界2:当i=0时,f[i][j]=f[0][j] = s2的n个值是否与s3的前n个值相等;遇到false后面可以直接省略
边界3:当j=0时,f[i][j]=f[i][0] = s1的m个值是否与s3的前m个值相等;遇到false后面可以直接省略
f[i,j]表示s1前i字符能否与s2前j字符组成s3前i+j个字符,也代表是否存在这么一个路径使得s1和s2能交叉拼接成s3。

bool isInterleave(string s1, string s2, string s3) 
{
	int m = s1.size(), n = s2.size(), t=s3.size();
	//f[i,j]表示s1前i字符能与s2前j字符组成s3前i+j个字符;
	auto f = vector<vector<int>> (m+1, vector<int>(n+1, false));
	
	//特殊处理
	if(m+n != t)
		return false;
	
	//边界1
	f[0][0] = true;
	//边界2	:不相符直接终止
	for(int i=1;i<m+1 && s1[i-1] == s3[i-1];i++)
		f[i][0] = true;
	//边界3:不相符直接终止
	for(int j=1;j<n+1;j++)
		f[0][j] = true;
	
	//处理
	for(int i=1;i<m+1;i++)
	{
		for(int j=1;j<n+1;j++)
		{
			int p = i+j-1;
			f[i][j] = (f[i-1][j] && (s1[i-1] == s3[p])) || (f[i][j-1] && (s2[j-1] == s3[p]));
		}
	}

	return f[m][n];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值