本题为美团秋招笔试题,原题描述如下:
使用字符“a”和字符"b"组成长度为n的字符串。要求不能包含“aba”和“bab”子串。求组成的字符串的个数。
1.本题最简便解法:斐波那契数列。
本题自己画一画,就可以发现规律是:2,4,6,10,16,26,··· 可以直接秒掉。但是本题是这个类型题目的一个特例,不属于通用解法。
2.最通用解法,树的层序遍历(BFS)
本题通用解法为:
1.维护一个队列,将第一层节点入队。
2.计算队列长度length,出队的同时,分别添加字符a或字符b作为左右子节点入队,在入队之前,检查新节点的尾部是否符合要求即可。(eg:原节点aaab,添加字符a后,变为aaaba,尾部出现非法子串,不入队,进行剪枝)。
3.循环至指定层即可。
4.此方法时间复杂度较高,但是最好理解。
代码如下:
q = ["a","b"]//初始化
n = 10 //测试长度
count = []
for i in range(n)://循环n次
l=len(q)
count.append(l)
for i in range(l):
temp = q.pop(0) //出队
a = temp + "a"
if a[-3:] != "aba": //检测入队
q.append(a)
b = temp + "b"
if b[-3:] != "bab":
q.append(b)
for i in range(n):
print(i+1,count[i])
3.另一种通用解法
详见此博客:https://www.cnblogs.com/kcn999/p/10659838.html
我们看另一个题目:用字符a,b,c组成长度为n的字符串,但是不能包含子串“aa”
用a[i]表示长度为i的方案数,用cnt表示a[i]中末尾为a的方案数,初始化为1。
则可得a[i]=a[i−1]∗3−cnt,cnt=a[i−1]−cnt。
由此可进行递推求解,类比到本题,就是:
用a[i]表示长度为i的方案数,用cnt表示a[i]中末尾为“ab”和“ba”的方案数,初始化为0。
则可得a[i]=a[i−1]∗3−cnt,cnt=a[i−1]−cnt。
这类题目本质是:a[i]=a[i−1]∗k−cnt, k为字符个数。 但是这里的cnt其实不太好推出来。
但如果有这个思路的话,利用方法二来找规律,利用方法三来编码也可以。
后续
对于字符a,和字符b组成的定长字符串,但是不能包含子串“abaa”。