小 V 有一个长度为 的字符串 ,其仅包含小写质字母。他可以对这个串做以下两种操作任意次: 删除这个字符串的第一个字符; 删除这个字符串的第二个字符,然后把左右两部分拼接起来。 小 V 想知道他一共可以得到多少种不同的字符串?注意:空串不计入答案内。
时间: 2024-10-24 08:17:12 浏览: 16
这是一个经典的动态规划问题,可以使用状态转移方程来解决。设 `dp[i]` 表示从原字符串的第一个字符开始到第 i 个字符结束时,所能得到的不同字符串的数量。
对于每个字符,有两种选择:
1. 如果我们保留当前字符,那么 `dp[i] = dp[i - 1]`,因为我们只是简单地到达了新的位置。
2. 如果我们删除当前字符,那么我们可以从下标 1 到 i - 1 的所有可能组合(即 `dp[1]` 到 `dp[i - 1]`)中选择一个,然后将它们与剩下的子串连接起来。所以 `dp[i]` 又增加了 `dp[j]` 对于所有 `1 <= j < i` 的值。
初始条件是 `dp[0] = 1`,因为没有字符时只有一个空串。
状态转移方程就是:
```cpp
dp[i] = dp[i - 1] + sum(dp[1] to dp[i - 1])
```
其中 `sum(dp[1] to dp[i - 1])` 是从 1 加到 (i - 1) 的所有 dp 值之和。这可以通过一个前缀和数组来计算,以便在常数时间内查找和累加。
以下是 C++ 代码实现:
```cpp
#include <vector>
int numDifferentStrings(std::string s, int n) {
std::vector<int> prefixSum(n);
for (int i = 1; i < n; ++i) {
prefixSum[i] = prefixSum[i - 1] + 1;
}
std::vector<int> dp(n + 1);
dp[0] = 1;
for (int i = 1; i <= n; ++i) {
dp[i] = dp[i - 1];
if (i >= 2) {
for (int j = 1; j < i; ++j) {
dp[i] += dp[j];
}
}
dp[i] -= prefixSum[i - 2]; // 减去重复计数的字符串
}
return dp[n];
}
```
阅读全文