查找禁止的字符串程序
Finding Forbidden Strings Program
我最近遇到了这个问题,如下所述:
如果有三个连续的字母,其中一个是A,一个是B,一个是C。例如,BAAAACABCCC是被禁止的,但AAABBBCCC不是。你得到一个整数 n。你必须找到有多少长度为 n 的字符串不被禁止。(n 将从 1 到 30)
示例:如果 n=2,则不禁止任何字符串。所以输出是 9。
我尝试过,但找不到有效的解决方案。我确实为此编写了一个蛮力算法,其中我检查了所有可能的此类字符串,但由于它是一个指数算法,所以它非常慢。你可以在这里找到我的代码
有人可以为此指导我一个高效的算法,也许使用动态规划或任何其他方式。
谢谢
从系列的外观来看:3,9,21,51,123 下一个数字是 123 * 2 + 51 = 297
动态规划可以在这里应用。
假设你知道 n = k 的非禁止序列的数量。现在,如果您添加另一个字母,则组合的数量将变为3k。但是,您必须丢弃被禁止的新组合。
任何序列的最后两个字母可以是:
ab
ac
bc
ba
ca
cb
bb
aa
cc
似乎形成了您提供的系列要丢弃的组合数 (k+1) = (k) 的新添加数
编辑:为什么会这样?假设在 3k 组合中,我们首先丢弃 k 组合,说在所有先前的序列中,我们将丢弃 1/3rd。
现在,在这些丢弃的k组合中,有一些组合的末尾有一个重复的字母(aa,bb或cc)。我们不必丢弃这些序列。
此类序列的数量应等于 (k-1) 的不禁止序列的数量,因为对于我们为 n=k 创建的每个新序列,我们可以有一个且只有一个重复字母的新序列。
Hence if f(k) = number of unforbidden combinations for n = k,
then f(k + 1) = 3f(k) - [f(k)-f(k-1)].
For example for n=3 the number of sequences with repeated letter at the end shall be 9.
For n=4 the number of sequences with repeated letter at the end shall be 21.
... and so on.
这种动态编程方法怎么样,其中C[x,y]
表示长度为 x
的不禁止字符串的数量,以 2 个字符序列y
结尾:
C [n, 'AA'] = C[n-1, 'AA'] + C[n-1, 'AB'] + C[n-1, 'AC']
C [n, 'AB'] = C[n-1, 'BA'] + C[n-1, 'BB']
C [n, 'AC'] = C[n-1, 'CA'] + C[n-1, 'CB'] + C[n-1, 'CC']
C [n, 'BA'] = C[n-1, 'AA'] + C[n-1, 'AB'] + C[n-1, 'AC']
C [n, 'BB'] = C[n-1, 'BA'] + C[n-1, 'BB'] + C[n-1, 'BC']
C [n, 'BC'] = C[n-1, 'CA'] + C[n-1, 'CB'] + C[n-1, 'CC']
C [n, 'CA'] = C[n-1, 'AA'] + C[n-1, 'AB'] + C[n-1, 'AC']
C [n, 'CB'] = C[n-1, 'BA'] + C[n-1, 'BB'] + C[n-1, 'BC']
C [n, 'CC'] = C[n-1, 'CA'] + C[n-1, 'CB'] + C[n-1, 'CC']
有边界条件n >= 3, C[3, x] = 3, C[3, 'AB'] = 2
?
还有一个简单的程序,不确定是否正确,但肯定足以冒一些反对票的风险,如果它是错误的,嘿嘿:)
#include <iostream>
unsigned int C[100][9];
// AA 0
// AB 1
// AC 2
// BA 3
// BB 4
// BC 5
// CA 6
// CB 7
// CC 8
void
calc (unsigned int n) {
unsigned int i;
for (i = 0; i < 9; ++i)
C[3][i] = 3;
C[3][1] = 2;
for (i = 4; i <= n; ++i) {
C[i][0] = C[i-1][0] + C[i-1][1] + C[i-1][2];
C[i][1] = C[i-1][3] + C[i-1][4];
C[i][2] = C[i-1][6] + C[i-1][7] + C[i-1][8];
C[i][3] = C[i-1][0] + C[i-1][1] + C[i-1][2];
C[i][4] = C[i-1][3] + C[i-1][4] + C[i-1][5];
C[i][5] = C[i-1][6] + C[i-1][7] + C[i-1][8];
C[i][6] = C[i-1][0] + C[i-1][1] + C[i-1][2];
C[i][7] = C[i-1][3] + C[i-1][4] + C[i-1][5];
C[i][8] = C[i-1][6] + C[i-1][7] + C[i-1][8];
}
}
// C [n, 'AA'] = C[n-1, 'AA'] + C[n-1, 'AB'] + C[n-1,'AC']
// C [n, 'AB'] = C[n-1, 'BA'] + C[n-1, 'BB']
// C [n, 'AC'] = C[n-1, 'CA'] + C[n-1, 'CB'] + C[n-1, 'CC']
// C [n, 'BA'] = C[n-1, 'AA'] + C[n-1, 'AB'] + C[n-1, 'AC']
// C [n, 'BB'] = C[n-1, 'BA'] + C[n-1, 'BB'] + C[n-1, 'BC']
// C [n, 'BC'] = C[n-1, 'CA'] + C[n-1, 'CB'] + C[n-1, 'CC']
// C [n, 'CA'] = C[n-1, 'AA'] + C[n-1, 'AB'] + C[n-1, 'AC']
// C [n, 'CB'] = C[n-1, 'BA'] + C[n-1, 'BB'] + C[n-1, 'BC']
// C [n, 'CC'] = C[n-1, 'CA'] + C[n-1, 'CB'] + C[n-1, 'CC']
int
main () {
for (unsigned int i = 3; i < 10; ++i) {
calc (i);
unsigned int s = 0;
for (unsigned int j = 0; j < 9; ++j)
s += C[i][j];
std::cout << s << " ";
}
}
对于i >= 2
:
设same[i]
以两个相同字符结尾的长度i
的允许(即不禁止)字符串的数量。
设diff[i]
以两个不同字符结尾的长度i
允许的字符串数。
然后same[2] = 3
,diff[2] = 6
,i >= 2
,
same[i+1] = same[i] + diff[i]
diff[i+1] = 2 * same[i] + diff[i]
我们想要的是n[i] = s[i] + d[i]
;上面的方程给了我们
n[2] = 9
n[i+1] = 2 * n[i] + n[i-1]
有了这个,您可以在基本上线性的时间内计算n[i]
。
- 重载操作程序时出错>>用于类中的字符串 memebr
- 为什么这个 c++ 代码打印出长度 5,当我打印出字符串时,程序会自动终止?
- 我的目标是编写一个程序来计算和存储字符串在字符数组中出现的位置
- 获取 OID(类型::b_oid)作为 MongoDB C++驱动程序中的字符串
- 重新运行程序和字符串流?
- 如何将字符串和整数读取到两个单独的动态数组中的程序编写?
- 如何使用将字符串拆分为 for 循环中的变量的程序
- win 表单应用程序字符串^ 到 int
- SDL2 程序只写入部分字符串
- 如何保护非托管应用程序中的字符串不受进程转储的影响
- C++程序在将 int 与 cin 一起使用时有效,但不能使用字符串
- 我的 c++ 程序似乎没有发现字符串和我拥有但输入使用 getline 的变量之间的比较
- 此程序不会打印整个字符串
- 用于拆分空格字符串的程序不起作用
- 为什么我的驱动程序只读取部分字符串?
- 为什么字符串类型会导致 c++ 程序无法运行?
- 程序检查字符串是否只包含 1 和 0?
- 使用终止程序的指针在数组中输入字符串
- OBDC 驱动程序字符串转换取决于控制面板/区域设置
- Mongodb c++驱动程序:字符串编码