LeetCode1079题:活字印刷——Python递归与迭代解法

1. LeetCode1079题:活字印刷

你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。

注意:本题中,每个活字字模只能使用一次。

示例 1:
输入:“AAB”
输出:8
解释:可能的序列为 “A”, “B”, “AA”, “AB”, “BA”, “AAB”, “ABA”, “BAA”。

示例 2:
输入:“AAABBC”
输出:188

提示:
1 <= tiles.length <= 7
tiles 由大写英文字母组成

2. 求字母序列数目的Python代码
2.1 递归
def numTilePossibilities(tiles):
    result = 0
    for i in set(tiles):
        result += 1 + numTilePossibilities(tiles.replace(i, '', 1))
    return result

print(numTilePossibilities('AAB'))
print(numTilePossibilities('AABC'))
print(numTilePossibilities('AAABBC'))

实验结果:
8
34
188

代码解读:
函数numTilePossibilities是一个递归函数,参数tiles代表活字字模上的字母组成的字符串,返回值result代表使用tiles中的字母能够排列出多少种字符串。

递归子问题:从tiles中拿出1个字母i后,使用剩余字母能够排列出多少种字符串。该问题在代码中表达为:numTilePossibilities(tiles.replace(i, '', 1))

若剩余字母排列出的字符串都加一个前缀i,即可得到一批新的字符串。由此可得,以字母i为前缀的字符串(包括字母i本身)共有1 + numTilePossibilities(tiles.replace(i, '', 1))种。

通过for i in set(tiles):遍历tiles去重后的字母集合,并使用result累计以不同字母为前缀的字符串的总数。

2.2 迭代
def numTilePossibilities(tiles):
    result = 0
    stack = [tiles]
    while stack:
        tiles = stack.pop()
        for i in set(tiles):
            result += 1
            stack.append(tiles.replace(i, '', 1))
    return result

print(numTilePossibilities('AAB'))
print(numTilePossibilities('AABC'))
print(numTilePossibilities('AAABBC'))

实验结果:
8
34
188

3. 求字母序列的Python代码
3.1 递归

递归代码对解空间树的搜索是深度优先搜索(depth first search, dfs)

def numTilePossibilities(tiles):
    result = []
    def dfs(tiles, prefix):
        for i in sorted(set(tiles)):
            result.append(prefix+i)
            dfs(tiles.replace(i, '', 1), prefix+i)
    dfs(tiles, '')
    return result

print(numTilePossibilities('AAB'))
print(numTilePossibilities('AABC'))

实验结果:
[‘A’, ‘AA’, ‘AAB’, ‘AB’, ‘ABA’, ‘B’, ‘BA’, ‘BAA’]
[‘A’, ‘AA’, ‘AAB’, ‘AABC’, ‘AAC’, ‘AACB’, ‘AB’, ‘ABA’, ‘ABAC’, ‘ABC’, ‘ABCA’, ‘AC’, ‘ACA’, ‘ACAB’, ‘ACB’, ‘ACBA’, ‘B’, ‘BA’, ‘BAA’, ‘BAAC’, ‘BAC’, ‘BACA’, ‘BC’, ‘BCA’, ‘BCAA’, ‘C’, ‘CA’, ‘CAA’, ‘CAAB’, ‘CAB’, ‘CABA’, ‘CB’, ‘CBA’, ‘CBAA’]

3.2 迭代(栈,深度优先搜索)

本迭代代码通过实现了对解空间树的深度优先搜索

def numTilePossibilities(tiles):
    result = []
    stack = [(tiles, '')]
    while stack:
        tiles, prefix = stack.pop()
        result.append(prefix)
        for i in sorted(set(tiles), reverse=True):
            stack.append((tiles.replace(i, '', 1), prefix+i))
    return result[1:]

print(numTilePossibilities('AAB'))
print(numTilePossibilities('AABC'))

实验结果:
[‘A’, ‘AA’, ‘AAB’, ‘AB’, ‘ABA’, ‘B’, ‘BA’, ‘BAA’]
[‘A’, ‘AA’, ‘AAB’, ‘AABC’, ‘AAC’, ‘AACB’, ‘AB’, ‘ABA’, ‘ABAC’, ‘ABC’, ‘ABCA’, ‘AC’, ‘ACA’, ‘ACAB’, ‘ACB’, ‘ACBA’, ‘B’, ‘BA’, ‘BAA’, ‘BAAC’, ‘BAC’, ‘BACA’, ‘BC’, ‘BCA’, ‘BCAA’, ‘C’, ‘CA’, ‘CAA’, ‘CAAB’, ‘CAB’, ‘CABA’, ‘CB’, ‘CBA’, ‘CBAA’]

3.3 迭代(栈)
def numTilePossibilities(tiles):
    result = []
    stack = [(tiles, '')]
    while stack:
        tiles, prefix = stack.pop()
        for i in sorted(set(tiles)):
            result.append(prefix+i)
            stack.append((tiles.replace(i, '', 1), prefix+i))
    return result

print(numTilePossibilities('AAB'))
print(numTilePossibilities('AABC'))

实验结果:
[‘A’, ‘B’, ‘BA’, ‘BAA’, ‘AA’, ‘AB’, ‘ABA’, ‘AAB’]
[‘A’, ‘B’, ‘C’, ‘CA’, ‘CB’, ‘CBA’, ‘CBAA’, ‘CAA’, ‘CAB’, ‘CABA’, ‘CAAB’, ‘BA’, ‘BC’, ‘BCA’, ‘BCAA’, ‘BAA’, ‘BAC’, ‘BACA’, ‘BAAC’, ‘AA’, ‘AB’, ‘AC’, ‘ACA’, ‘ACB’, ‘ACBA’, ‘ACAB’, ‘ABA’, ‘ABC’, ‘ABCA’, ‘ABAC’, ‘AAB’, ‘AAC’, ‘AACB’, ‘AABC’]

3.4 迭代(队列)

本迭代代码通过队列实现了对解空间树的广度优先搜索(breadth first search, bfs)

def numTilePossibilities(tiles):
    result = []
    queue = [(tiles, '')]
    while queue:
        tiles, prefix = queue.pop(0)
        for i in sorted(set(tiles)):
            result.append(prefix+i)
            queue.append((tiles.replace(i, '', 1), prefix+i))
    return result

print(numTilePossibilities('AAB'))
print(numTilePossibilities('AABC'))

实验结果:
[‘A’, ‘B’, ‘AA’, ‘AB’, ‘BA’, ‘AAB’, ‘ABA’, ‘BAA’]
[‘A’, ‘B’, ‘C’, ‘AA’, ‘AB’, ‘AC’, ‘BA’, ‘BC’, ‘CA’, ‘CB’, ‘AAB’, ‘AAC’, ‘ABA’, ‘ABC’, ‘ACA’, ‘ACB’, ‘BAA’, ‘BAC’, ‘BCA’, ‘CAA’, ‘CAB’, ‘CBA’, ‘AABC’, ‘AACB’, ‘ABAC’, ‘ABCA’, ‘ACAB’, ‘ACBA’, ‘BAAC’, ‘BACA’, ‘BCAA’, ‘CAAB’, ‘CABA’, ‘CBAA’]

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值