查找有效字符串

时间:2017-10-19 13:12:53

标签: python python-3.x

当且仅当字符串中只有两个字符ab时才有效(不一定a应该存在)并且它必须有三个b&#39 ; s为了有效而连续进入。例如,对于长度为n=4 [bbbb,bbba,abbb]的字符串,有效字符串是完全有效的字符串为3,对于n=3,只有一个有效字符串[bbb]。 n可以是最大10 ** 4的任何整数。我解决这个问题的方法可能很幼稚,因为我是编程新手,但这就是我的开始:

import itertools
x=list(input().strip())
test=True
lis=[]
for _ in (x):
    if _ == 'a' or _=='b':
        continue
    else:
        test=False
        break

if test:
    y=list(itertools.permutations(x))
    print(y)

现在我正在寻找n=5,6,7的模式,然后为常规实现它,但我想要消除列表y中不满足上述条件的所有无效字符串。我需要打印计数一个特定整数n的所有有效字符串,对应于字符串的长度。

4 个答案:

答案 0 :(得分:1)

一个简单的方法是生成一定长度的字符串的所有可能的组合,只有字符'a'和'b',然后测试它们内部是否有'bbb'模式。

def recursive_function(n, seed=None, chars="ab"):
    if seed is None:
        seed = ['']
    result = []
    for char in chars:
        result.extend(list(map(lambda x: x + char, seed)))
    if n-1:
        return recursive_function(n-1, result, chars)
    else:
        return result

unfiltered = recursive_function(5)

filtered = list(filter(lambda x: 'bbb' in x, unfiltered))

print(filtered)

该函数会在参数str中的每个seed附加chars中的选项。如果seed = ['var']chars = "12" => result = ['var1', 'var2']。在此之前,如果我们不提供,我们会创建一个空list的{​​{1}}。在它之后,我们检查我们是否达到了所需的长度或打电话给自己,但将str减少了1。

这会生成一个长度等于n变量长度的列表,其强度为charsn。这意味着你很快就会内存不足n = 100会给我内存问题,取决于你的设置,设置......

然后我们使用len(chars)**n函数对其进行过滤并将其转换回list,该函数检查它是否具有子串lambda

另一个解决方案是使用itertools:

'bbb'

我为@DanielTrugman@PM2Ring提取的每个步骤提供了一些替代方案,它们的任何组合都应该有效。这种新方法的关键点在于它们永远不会创建from itertools import product unfiltered = map(''.join, product('ab', repeat=5)) #unfiltered = (''.join(x) for x in product('ab', repeat=5)) # suggested by @DanielTrugman filtered = filter(lambda x: 'bbb' in x, unfiltered) #filtered = (x for x in unfiltered if 'bbb' in x) # suggested by @DanielTrugman i = sum(1 for _ in filtered) # suggested by @PM2Ring #for i, _ in enumerate(filtered): # pass #i += 1 #i = 0 #for _ in filtered: # i += 1 print(i) ,它之前会产生内存问题,它们正在创建生成器。生成器可以用于生成下一个元素,可以在list循环中使用,但不会将完整内容存储在内存中(这也意味着一旦我遍历生成器,我需要再次创建它)如果我想在另一个for循环中使用它。通过使用枚举,每个元素被转换为形式为for的元组,其中i是从0开始的自动递增整数,因此当循环结束(i, element)等于元素数减1.时替代此元素最后一部分是手动完成。

请记住,在第二次生成器为空时,您不能同时使用它们,要么重新创建它,重新执行未过滤和已过滤的部分,要么只使用其中一种方法。

注意:这将使用N = 10 ^ 5

A further answer之前的@PM2Ring提供了有关如何使用数值公式计算结果的信息,该数值公式将会迭代可能性,即使它们使用生成器也是如此。

答案 1 :(得分:1)

您可以使用它来生成给定长度n的所有可能组合,然后过滤无效的组合。

使用理解的更快的方法(更喜欢较小的n值):

n = 10
combinations = [''.join(x) for x in itertools.product('ab', repeat=n)]
valid = [x for x in combinations if 'bbb' in x]
print len(valid)

使用生成器的RAM高效方法(更喜欢更大的n值):

n = 10
combinations = (''.join(x) for x in itertools.product(['a', 'b'], repeat=n))
valid = (x for x in combinations if 'bbb' in x)
print sum(1 for _ in valid)

答案 2 :(得分:1)

我们可以使用itertools.product轻松生成有效的字符串,以生成' a'和' b'在所需长度中,将元组加入字符串,然后过滤掉不包含' bbb'。

的字符串。

我们不需要将所有字符串存储在列表中。相反,我们使用生成器函数生成它们。

要计算给定长度的有效字符串数量,我们仍然不需要制作列表。我们可以使用内置的求和函数和生成器表达式轻松计算生成器产生的字符串。

这是一个简短的演示。

from itertools import  product

def make_valid(n):
    for s in map(''.join, product('ab', repeat=n)):
        if 'bbb' in s:
            yield s

# Print all the valid strings for n = 5
for i, t in enumerate(make_valid(5), 1):
    print(i, t)
print()

# Count the number of valid strings for some small values of n
for n in range(16):
    print(n, sum(1 for _ in make_valid(n)))
print()

<强>输出

1 aabbb
2 abbba
3 abbbb
4 babbb
5 bbbaa
6 bbbab
7 bbbba
8 bbbbb

0 0
1 0
2 0
3 1
4 3
5 8
6 20
7 47
8 107
9 238
10 520
11 1121
12 2391
13 5056
14 10616
15 22159

此策略适用于小n,但我们需要一个公式来计算较大n的计数。幸运的是,这个序列可以在OEIS中找到序列A050231,它列出了一些有用的公式。它甚至有一些Python代码,尽管我们可以使用不同的公式来提高效率。使用此公式,我们可以轻松计算大n的计数,但对于n > 1000,我们可能需要增加递归限制(取决于cache字典中的内容)。

import sys

def valid_num(n, cache={0:0, 1:0, 2:0, 3:1, 4:3}):
    if n in cache:
        return cache[n]
    v = cache[n] = 2 * valid_num(n-1) - valid_num(n-4) + (1 << (n-4))
    return v

# Calculate the same counts using the formula
for n in range(16):
    print(n, valid_num(n))
print()

# Calculate some larger counts using the formula
for n in (20, 100, 1000):
    print(n, valid_num(n))
print()

# Calculate the count for n = 10000
sys.setrecursionlimit(10000)
n = 10000
v = valid_num(n)
print(n, 'length:', len(str(v)))
print(v)

<强>输出

0 0
1 0
2 0
3 1
4 3
5 8
6 20
7 47
8 107
9 238
10 520
11 1121
12 2391
13 5056
14 10616
15 22159

20 825259
100 1267318799554307616411887824515
1000 10715086071862673209484250490600018100539745081012589876867705301975463230239516162056449817835254127137269714485423444296635751843450469485667983663407684446390757637525684523851088159545633725265629658895944476385164970179813685921539685461239078098993547717387680879133627403305119486713242032255067

10000 length: 3011
19950631168807583848837421626835850838234968318861924548520089498529438830221946631919961684036194597899331129423209124271556491349413781117593785932096323957855730046793794526765246551266059895520550086918193311542508608460618104685509074866089624888090489894838009253941633257850621568309473902556912388065225096643874441046759871626985453222868538161694315775626089623134328073983786389675177701186558011272310697526877798064028762732641567763583009365923237958579619694722743012623795847397854998863572912757259022370929851354671535479510177534365020486167704487189515540498377935792784729998056204236193219552902248837389484924415956257294989763770669720233733644286583000382759075539053082652941408713883472715627420221687140691149326172458181449913074158357403912912879276902845540785568622960033810574475726502542130288984975487755939111059374407249361193935123107325839835567845152301152599696481119763066457621100802588552680671318557266858044791840868082518099393177406617354957371241176940107570738702088618534197370980151722230231186806124846732235800482635363983329963660230357785349549545506065669831114315218532610109374476503772297612747522883328342787820540011850973090403518483383437648807620569472507786915081183978792023340064365641436883629372337926937368346416759281652638487818090591411436604449009422265319311879409918048008416090298359064134661715823412371674763461157363128721685818760472532914713274785795923563234731723132316960019917396064130633819807185968362914576441538717071994274286406827253010143879860255399415078316174263450870289088692073427388192608054285426524914418151339875321474768984105710841294710811517295773844059882211433112941200409216807692338045919038698016225727309613247405118664483317505367054663735478905020533879998277077423479999938238338161234544356443164377399933151023535182334388940451107785030288175719971170053676007075190227062172140481425461917515455479972068054339784181607496627198030056906424447389442115111598117425687643181400799735513708227684305240112451551816573610657557740466165389046532852242049143998343971456857060951994667027419070327679375387245482516968508426783900751557991025654896592270261372186844112570682419026071390817038382780816857411320558427785718592835834380922916168890933210737876196968898314180514932819277476011379800392972374348601006573628313908492614955299976109070068900439705816010323545500438056558640731711137133200529511554379646269211769945584022230495812252890259551503449397117011713619252886812420071394209078307064109175851940790347483097635133334458431432349757774924271783333143566842831599567399569263816537290034939347896683277449442140167815797283546947849352457384014905698858773315056621125677551281637613936596108267979291171314129517832750587062076381907831127494015516619913002000219217551370967381359461580273960378080346580481200727681280258846559027048156913034694942538168049000091115128411182728198666360471953351549972522903396839735125178400179203500439758780473093919765016217623879

Adirio在评论中提到我们不需要使用4: 3初始化缓存,并且我们可以通过使用列表而不是缓存的dict来使这个版本更高效。这是有效的,因为递归可以保证添加到缓存中的任何新项目的索引1始终大于缓存中当前最后一项的索引。

以下是改进版本:

def valid_num(n, cache=[0, 0, 0, 1]):
    if n >= len(cache):
        cache.append(2 * valid_num(n-1) - valid_num(n-4) + (1 << (n-4)))
    return cache[n]

谢谢,阿迪里奥!

答案 3 :(得分:0)

这可以通过使用简单的正则表达式匹配来完成。首先检查字符串是否只包含a和b。然后,使用itertools创建所有组合,并使用正则表达式过滤所需的组合。

def return_valid_strings(string):
    if re.match("^[ab]*$", string):
        y = ["".join(x) for x in itertools.permutations(string) if re.match("^[ab]*bbb[ab]*$", "".join(x))]
    return list(set(y))