博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
LeetCode 115 Distinct Subsequences--In C++
阅读量:4090 次
发布时间:2019-05-25

本文共 1232 字,大约阅读时间需要 4 分钟。

思路:

这个问题让人联想到最长公共子序列的问题,因此可以用动态规划的问题来解决。最难的部分在于状态迁移的实际含义,这点好推出来,却很难理解。

和最长公共子序列的问题一样,用dp[i][j]的数组来表示状态,含义为在s中取i个字符,在t中取j个字符,s中i个字符能够得到多少个t中j个字符组成的序列。很明显当j大于i时,结果一定为0。当j等于0时,结果一定为1。这就是边界条件了。

同时注意到,当i大于j时(其实大不大于无关紧要,只是为了好理解一些),无论i的最后一个字符是什么,dp[i][j]都至少要等于dp[i-1][j],因为s延长了,解不可能比s更短时还要小。例如s=“abc%”,t="abc",则无论%代表什么,解的数量至少为s="abc",t="abc"的解。可以直观认识到,当%不等于‘c’时,其实两种情况解数量是相等的。

关键点在于%等于‘c’时怎么办?怎么表示‘净’多出来的解的数量?

我的理解是:首先看待继承自dp[i-1][j]的那部分解数时,不考虑%,也就是说%“一定不“参与匹配,无论%代表c还是不是c。等到考虑净多出来的部分时,%”一定“参与匹配,我们可以将t中的最后一个字符和%”固定“匹配起来,这样净多出来的数量应该是dp[i-1][j-1]。从集合的角度来讲”一定不“和”一定“两种情况没有交集,并且并集为全集。

这样得到递推式dp[i][j] = dp[i-1][j] (s[i-1]!=t[j-1])和dp[i][j] = dp[i-1][j] + dp[i-1][j-1] (s[i-1]==t[i-1])

int numDistinct(string s, string t) {	int m = s.size();	int n = t.size();		int* * dp = new int*[m+1];	for (int i = 0; i < m + 1;i++){		dp[i] = new int[n + 1]{0};	}	for (int i = 0; i < m + 1;i++){		dp[i][0] = 1;//任何串到""都是1种情况	}	for (int i = 0; i < m + 1;i++){		for (int j = 1; j < n + 1;j++){			if (j>i){				dp[i][j] = 0;				continue;			}			if (s[i-1]==t[j-1]){				dp[i][j] = dp[i - 1][j - 1] + dp[i-1][j];			}			else{				dp[i][j] = dp[i - 1][j];			}		}	}	int result = dp[m][n];	for (int i = 0; i < m + 1;i++){		delete[] dp[i];	}	delete[] dp;	return result;}

转载地址:http://ubdii.baihongyu.com/

你可能感兴趣的文章
webpack的面试题总结
查看>>
实践这一次,彻底搞懂浏览器缓存机制
查看>>
Koa2教程(常用中间件篇)
查看>>
React Hooks 完全指南
查看>>
React16常用api解析以及原理剖析
查看>>
教你发布你npm包
查看>>
nvm 和 nrm 的安装与使用
查看>>
React Hooks 一步到位
查看>>
React Redux常见问题总结
查看>>
前端 DSL 实践指南
查看>>
ReactNative: 自定义ReactNative API组件
查看>>
cookie
查看>>
总结vue知识体系之实用技巧
查看>>
PM2 入门
查看>>
掌握 TS 这些工具类型,让你开发事半功倍
查看>>
前端如何搭建一个成熟的脚手架
查看>>
Flutter ListView如何添加HeaderView和FooterView
查看>>
Flutter key
查看>>
Flutter 组件通信(父子、兄弟)
查看>>
Flutter Animation动画
查看>>