1. Leetcode 96:给定一个数字,输出从1至该数所能构成的BST(二叉搜索树)
class Solution {
public:
int numTrees(int n) {
if(n==0||n==1)
return n;
vector<int> ans;
ans.push_back(1);
ans.push_back(1);
for(int i=2;i<=n;++i)
{
int tempsum = 0;
for(int j=0;j<=i-1;++j)
{
tempsum += ans[j]*ans[i-1-j];
}
ans.push_back(tempsum);
}
return ans.back();
}
};
2.Leetcode 97:
Interleaving String
Given s1, s2, s3, find whether s3 is formed by the interleaving of s1 and s2.
For example,
Given:
s1 = "aabcc"
,
s2 = "dbbca"
,
When s3 = "aadbbcbcac"
, return true.
When s3 = "aadbbbaccc"
, return false.
可以用递归做,每匹配s1或者s2中任意一个就递归下去。但是会超时。
因此考虑用动态规划做。
s1, s2只有两个字符串,因此可以展平为一个二维地图,判断是否能从左上角走到右下角。
当s1到达第i个元素,s2到达第j个元素:
地图上往右一步就是s2[j-1]匹配s3[i+j-1]。
地图上往下一步就是s1[i-1]匹配s3[i+j-1]。
示例:s1="aa",s2="ab",s3="aaba"。标1的为可行。最终返回右下角。
class Solution {public:
bool isInterleave(string s1, string s2, string s3) {
int len1 = s1.size(), len2 = s2.size(), len3 = s3.size();
if (len1 + len2 != len3)
return false;
vector<vector<bool>> path(len1 + 1, vector<bool>(len2 + 1,false));
for (int i = 0; i <= len1; ++i)
{
for (int j = 0; j <= len2; ++j)
{
if (i == 0 && j == 0)
{
path[i][j] = true;
}
else if (i == 0)
{
path[i][j] = path[i][j-1]&(s3[j - 1] == s2[j - 1]);
}
else if (j == 0)
{
path[i][j] = path[i-1][j]&(s3[i - 1] == s1[i - 1]);
}
else
{
path[i][j] = (path[i][j-1]&(s3[i+j-1]==s2[j-1]))||(path[i-1][j]&(s3[i+j-1]==s1[i-1]));
}
}
}
return path[len1][len2];
}
};
3. LeetCode 115:
Given a string S and a string T, count the number of distinct subsequences of T in S.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE"
is a subsequence of "ABCDE"
while "AEC"
is not).
Here is an example:
S = "rabbbit"
, T = "rabbit"
Return 3
.
看到有关字符串的子序列或者配准类的问题,首先应该考虑的就是用动态规划Dynamic Programming来求解,这个应成为条件反射。而所有DP问题的核心就是找出递推公式,想这道题就是递推一个二维的dp数组,下面我们从题目中给的例子来分析,这个二维dp数组应为:
Ø r a b b b i t Ø 1 1 1 1 1 1 1 1 r 0 1 1 1 1 1 1 1 a 0 0 1 1 1 1 1 1 b 0 0 0 1 2 3 3 3 b 0 0 0 0 1 3 3 3 i 0 0 0 0 0 0 3 3 t 0 0 0 0 0 0 0 3
首先,若原字符串和子序列都为空时,返回1,因为空串也是空串的一个子序列。若原字符串不为空,而子序列为空,也返回1,因为空串也是任意字符串的一个子序列。而当原字符串为空,子序列不为空时,返回0,因为非空字符串不能当空字符串的子序列。理清这些,二维数组dp的边缘便可以初始化了,下面只要找出递推式,就可以更新整个dp数组了。我们通过观察上面的二维数组可以发现,当更新到dp[i][j]时,dp[i][j] >= dp[i][j - 1] 总是成立,再进一步观察发现,当 T[i - 1] == S[j - 1] 时,dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1],若不等, dp[i][j] = dp[i][j - 1],所以,综合以上,递推式为:
dp[i][j] = dp[i][j - 1] + (T[i - 1] == S[j - 1] ? dp[i - 1][j - 1] : 0)
代码:
static int x = [](){
std::ios::sync_with_stdio(false);
cin.tie(NULL);
return 0;
}();
class Solution {
public:
int numDistinct(string s, string t) {
int lens = s.size();
int lent = t.size();
vector<vector<int>> method(lent+1,vector<int>(lens+1,0)); //初始化
for(int i=0;i<=lens;++i)
{
method[0][i] = 1;
}
for(int i=1;i<=lent;++i)
{
method[i][0] = 0;
}
for(int i=1;i<=lent;++i)
{
for(int j=1;j<=lens;++j)
{
if(t[i-1]!=s[j-1])
{
method[i][j] = method[i][j-1];
}
else
{
method[i][j] = method[i][j-1]+method[i-1][j-1];
}
}
}
return method[lent][lens];
}
};
4. LeetCode 132 Palindrome Partitioning II
Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
Example:
Input: "aab" Output: 1 Explanation: The palindrome partitioning ["aa","b"] could be produced using 1 cut.
代码:
// static int x = []()
// {
// std::ios::sync_with_stdio(false);
// cin.tie(NULL);
// return 0;
// }();
class Solution {
public:
int minCut(string s) {
vector<vector<int>>dp(s.size(),vector<int>(s.size(),0));
vector<int>palin(s.size()+1,0);
for(int i=s.size()-1;i>=0;--i)
{
palin[i] = INT_MAX;
for(int j=i;j<s.size();++j)
{
if(s[i]==s[j]&&(j-i<=1||1==dp[i+1][j-1]))
{
dp[i][j] = 1;
palin[i] = min(1+palin[j+1],palin[i]);
}
}
}
return palin[0]-1;
}
};