LeetCode Distinct Subsequences

本文探讨了一种计算字符串子序列数量的有效方法。通过递归、动态规划及优化技巧,对比了不同实现方式的效率。特别关注如何使用一维数组替代传统二维数组以减少空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题有有意思,比前面的题好多了,刚开始时理解题意有误,就是没明白什么意思,看了别人的博客才明白。之后就是方法的问题,递归,动态规划,然后是动态规划的优化,不优化的动态规划不通过。所谓的优化,其实就是用一维数组代替DP的二维数组,dp式子dp[i][j]=dp[i-1][j-1]+dp[i-1][j](S[i]==T[j])时;dp[i][j]=dp[i-1][j](S[i]!=T[j])时;只要是这种形式的,有一维的索引下标每次都递减的情况就可以优化,不满足这样的式子不能优化。还要注意的是优化后的式子if (S[i-1]==T[j-1]) dp[j] = dp[j-1] + dp[j];for循环j要从大到小,否则回新的值会覆盖原来的值,等式右边是原来的值,左侧是更新的值。三种方法代码如下:

// LeetCode_Distinct Subsequences.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;

int numDistinctRecursive(string &S,int i,string &T,int j)
{
	if(i<j)
		return 0;
	if(j<0)
		return 1;
	if(i==j&&S[i]!=T[j])
		return 0;
	if(S[i]==T[j])
		return numDistinctRecursive(S,i-1,T,j-1) + numDistinctRecursive(S,i-1,T,j);
	else
		return numDistinctRecursive(S,i-1,T,j);
}
int numDistinct(string S, string T) {
	if(S.length()<T.length())
		return 0;
	if(S.empty()||T.empty())
		return 0;
	return numDistinctRecursive(S,S.length()-1,T,T.length()-1);
}

int numDistinct02(string S, string T) {
	int lens = S.length();
	int lent = T.length();
	if(lens<lent)
		return 0;
	if(lens==0||lent==0)
		return 0;
	int dp[500][500];
	if(S[0]==T[0])
		dp[0][0] = 1;
	else
		dp[0][0] = 0;
	for (int k=1;k<lens;k++)
	{
		if (S[k]==T[0])
			dp[k][0] = dp[k-1][0] + 1;
		else
			dp[k][0] = dp[k-1][0];
	}
	for (int j=1;j<lent;j++)
	{
		for (int i=0;i<lens;i++)
		{
			if(j>i)
				dp[i][j] = 0;
			else
			{
				if (S[i]==T[j])
					dp[i][j] = dp[i-1][j-1] + dp[i-1][j];
				else
					dp[i][j] = dp[i-1][j];
			}
		}
	}
	return dp[lens-1][lent-1];
}

int numDistinct03(string S, string T) {
	int lens = S.length();
	int lent = T.length();
	if(lens<lent)
		return 0;
	if(lens==0||lent==0)
		return 0;
	int dp[10000];
	dp[0] = 1;
	for (int k=1;k<=lent;k++)
		dp[k] = 0;
	for (int i=1;i<=lens;i++)
	{
		for (int j=lent;j>=1;j--)// otherwise overlapped
		{
			if (S[i-1]==T[j-1])
				dp[j] = dp[j-1] + dp[j];
		}
	}
	return dp[lent];
}

int _tmain(int argc, _TCHAR* argv[])
{
	string s,t;
	while(cin>>s&&cin>>t)
	{
		cout<<numDistinct(s,t)<<endl;
		cout<<numDistinct02(s,t)<<endl;
		cout<<numDistinct03(s,t)<<endl;
	}
	system("pause");
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值