题目链接:https://www.codewars.com/kata/5426d7a2c2c7784365000783/python
我的解决方案:
def balanced_parens(n):
# Your code here!
used_l=[False for i in range(n)]
used_r=[False for i in range(n)]
answers=[]
def process(answer):
if len(answer)==2*n:
answers.append(answer)
return
for i in range(n):
if used_l[i]:
continue
if i>0 and not used_l[i-1]:
continue
used_l[i]=True
process(answer+'(')
used_l[i]=False
if used_r.count(False)>used_l.count(False):
for i in range(n):
if used_r[i]:
continue
if i>0 and not used_r[i-1]:
continue
used_r[i]=True
process(answer+')')
used_r[i]=False
process('')
return answers
print(balanced_parens(3))
这个解决方法借鉴了这篇文章里对itertools.permutations
的优化。
itertools
中的permutations
的参数是一个可进行遍历操作的变量(比如列表,元组,字符串等),返回的是这个变量中所有元素的排列组合的所有可能。如:
from itertools import permutations
a=[1,2,3]
print(permutations(a))
for i in permutations(a):
print(i,end=' ')
'''输出
<itertools.permutations object at 0x00000191DC5A3740>
(1, 2, 3) (1, 3, 2) (2, 1, 3) (2, 3, 1) (3, 1, 2) (3, 2, 1)
'''
permutations
函数还可以加入一个整数参数表示进行排列组合时取出的元素个数,没有该参数的话默认取出全部元素。permutation(a,2)
返回的是从a中取出两个元素放在两个不同的位置上,所有的可能的结果
from itertools import permutations
a=[1,2,3]
print(permutations(a,2))
for i in permutations(a,2):
print(i,end=' ')
'''输出
<itertools.permutations object at 0x000001DD1B9B3600>
(1, 2) (1, 3) (2, 1) (2, 3) (3, 1) (3, 2)
'''
如果传入的序列变量中有重复的元素,那函数返回的结果中也会有重复的元素(组合)
from itertools import permutations
a=[1,1,3]
print(permutations(a))
for i in permutations(a):
print(i,end=' ')
'''输出
<itertools.permutations object at 0x000001D12F113600>
(1, 1, 3) (1, 3, 1) (1, 1, 3) (1, 3, 1) (3, 1, 1) (3, 1, 1)
'''
文章里写了一个新的permutations函数可以避免重复,如下:
class MyItertools:
#排列组合时取出元素个数用默认参数L定义
def permutations(self,nums,L=-1):
#当传入了参数L且符合逻辑时,使用传入的参数作为返回长度
#否则使用nums的长度,即取出所有元素进行排列组合
L = len(nums) if L<=0 or L>len(nums) else L
#对nums进行排序,使相同元素相邻
nums.sort()
#生成与nums等长的标记数组,用于标识nums中的元素是否已被取出
used=[False for i in nums]
#储存所有排列组合的结果
results=[]
def get_one(result):#每次调用函数,处理result剩余未放置元素的所有组合可能性
if len(result)==L:
#已经取出足够数量的元素,成功获得了一个排列组合结果
results.append(result)
return
#i和value分别是下标和值
#每次调用函数取出一个元素参与排列,而nums中所有尚未被取出的元素都有被取出的可能
#遍历每种可能
for i,value in enumerate(nums):
#如果nums[i]已经被取出则跳过
if used[i]:
continue
#排列结果重复的根本原因是在一种排列组合中交换两个元素位置后结果不变
#交换两个相同元素不会改变排列组合
#为保证排列结果没有重复,要保证nums中相同的元素在排列时相对顺序不变
#即不会只在相同元素直接互相交换去制造新的组合
#要做到这一点,可保证相同元素只有前面的元素被取出参与排列后才会取出后面元素
#如果nums[i]与它前面的元素的值相同,且前面的元素尚未被取出,则跳过该元素
if i>0 and value==nums[i-1] and not used[i-1]:
continue
#上面的条件都为满足,说明该元素(nums[i])可被取出
used[i]=True#取出元素
get_one(result+[value])#处理这个位置放置这个元素的所有可能性
used[i]=False#处理之后取回该元素,继续循环,探索该位置放置其它元素的可能
get_one([])
return results
if __name__=='__main__':
for i in MyItertools().permutations([1,2,3]):
print(i,end=' ')
【 All Balanced Parentheses】这个题目也相当于对n个'('
和n个')'
进行排列组合,每次组合时,对所有可放置元素进行遍历。这个题对可放置元素有限制,因为要符合括号闭合的规则,只有已放置多余的'('
时才能放置')'
。因为'('
与')'
都相当于相同元素,于是我就用了上面的方法避免重复