Ruby 打印n对括号的所有有效组合的算法
我正在研究问题陈述中所述的问题。我知道我的解决方案是正确的(运行了程序),但我很好奇我是否正确地分析了我的代码(如下)Ruby 打印n对括号的所有有效组合的算法,ruby,algorithm,recursion,time-complexity,space-complexity,Ruby,Algorithm,Recursion,Time Complexity,Space Complexity,我正在研究问题陈述中所述的问题。我知道我的解决方案是正确的(运行了程序),但我很好奇我是否正确地分析了我的代码(如下) def parens(num) return ["()"] if num == 1 paren_arr = [] parens(num-1).each do |paren| paren_arr << paren + "()" unless "()#{paren}" == "#{paren}()" paren_arr << "
def parens(num)
return ["()"] if num == 1
paren_arr = []
parens(num-1).each do |paren|
paren_arr << paren + "()" unless "()#{paren}" == "#{paren}()"
paren_arr << "()#{paren}"
paren_arr << "(#{paren})"
end
paren_arr
end
以下是我的分析:
每个f(n)值大约是f(n-1)元素数的3倍。因此:
f(n)=3*f(n-1)=3*3*f(n-2)~(3^n)时间成本。
通过类似的分析,堆栈将被f(1)…f(n)占用,因此空间复杂度应为3^n
我不确定这种时间或空间分析是否正确。一方面,堆栈只包含n个函数调用,但每个调用返回的数组都是前一个调用的3倍。这个因素会影响空间成本吗?我的时间分析正确吗?我发现Tom Davis的“加泰罗尼亚数字”非常有助于解释一种定义时间的递归方法。我将试着自己解释它(部分是为了看看我理解了多少),因为它可以用于查找N
匹配括号的所有唯一排列(例如,1();2(),(())等)
对于
N>1
让(A)B
表示匹配括号的一种排列方式,其中A
和B
仅具有平衡的括号集。然后我们知道,如果A
包含k
匹配集,B
必须有另一个N-k-1
,其中0,正如其他人所提到的,您的解决方案是不正确的
我最喜欢的解决方案是通过将当前字符串重复递增到词汇上的下一个有效组合来生成所有有效组合
“词汇上的下一步”分解为几个规则,使其变得非常简单:
- 字符串中的第一个差异将“(”更改为“)”。否则,下一个字符串将在词汇上位于当前字符串之前
- 第一个区别是尽可能向右。否则会有较小的增量
- 第一个差异之后的部分在词汇上是最小的,这也是因为否则会有较小的增量。在本例中,这意味着所有的“(”在所有的“')之前
因此,您所要做的就是找到最右边的“(”可以更改为“)”,翻转它,然后添加正确数量的“('s and')”
我不知道Ruby,但在Python中它看起来是这样的:
current="(((())))"
while True:
print(current)
opens=0
closes=0
pos=0
for i in range(len(current)-1,-1,-1):
if current[i]==')':
closes+=1
else:
opens+=1
if closes > opens:
pos=i
break
if pos<1:
break
current = current[:pos]+ ")" + "("*opens + ")"*(closes-1)
对于许多类型的“生成所有组合”问题,像这样的解决方案变得简单而快速。递归推理是一个简单的解决方案。如果剩余要发射的左paren数为正,则发射一个并重复。如果剩余要发射的右paren数大于左paren数,请发射并重复。基本情况是当所有的paren(包括左侧和右侧)都已发出时。印刷品
def parens(l, r = l, s = "")
if l > 0 then parens(l - 1, r, s + "(") end
if r > l then parens(l, r - 1, s + ")") end
if l + r == 0 then print "#{s}\n" end
end
正如其他人所说,加泰罗尼亚数字给出了要打印的字符串的数量
虽然这个Ruby实现没有实现它,但是一种较低级别的语言(如C)可以使使用单个字符串缓冲区变得容易:O(n)空间。由于子字符串的拷贝,这个是O(n^2)。但是,由于运行时和输出长度是O(n!),O(n)空间效率低下并不意味着什么。您的解决方案不正确<代码>参数(4)
将不包括“(())(())”
。多么漂亮的解决方案!
. () = AB = C_0C_1 => (.)()
() . = AB = C_1C_0 => (()) .
C_0C_2 = AB = . ()() and . (()) => ()()(), ()(())
C_1C_1 = AB = ()() => (())()
C_2C_0 = AB = ()() . and (()) . => (()()), ((()))
current="(((())))"
while True:
print(current)
opens=0
closes=0
pos=0
for i in range(len(current)-1,-1,-1):
if current[i]==')':
closes+=1
else:
opens+=1
if closes > opens:
pos=i
break
if pos<1:
break
current = current[:pos]+ ")" + "("*opens + ")"*(closes-1)
(((())))
((()()))
((())())
((()))()
(()(()))
(()()())
(()())()
(())(())
(())()()
()((()))
()(()())
()(())()
()()(())
()()()()
def parens(l, r = l, s = "")
if l > 0 then parens(l - 1, r, s + "(") end
if r > l then parens(l, r - 1, s + ")") end
if l + r == 0 then print "#{s}\n" end
end