查找格式正确的括号的所有组合
这是在与朋友交谈时提出的,我想我应该在这里问,因为这是一个有趣的问题,并且希望看到其他人的解决方案。
任务是编写一个函数 Brackets(int n),打印 1...n 中所有格式良好括号的组合。 对于括号(3),输出将是
()
(()) ()()
((())) (()()) (())() ()(()) ()()()
This came up while talking to a friend and I thought I'd ask here since it's an interesting problem and would like to see other people's solutions.
The task is to write a function Brackets(int n) that prints all combinations of well-formed brackets from 1...n. For Brackets(3) the output would be
()
(()) ()()
((())) (()()) (())() ()(()) ()()()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(30)
红宝石版本:
ruby version:
另一个低效但优雅的答案=>
Another inefficient but elegant answer =>
记忆化的尝试:
An attempt with memoization:
调用者 -
function(2*brackets, str, 0, 0);
Caller -
function(2*brackets, str, 0, 0);
我今天在接受采访时被问到这个问题。
我总是在《破解编码》中跳过这个问题,因为我认为这对于面试来说是一个愚蠢的问题。 但面试官并没有同意我的观点。
以下是我在采访中可能提出的解决方案。 面试官正在寻找上面已经给出的更高效的方法。 但他通过了我的解决方案。
其他性能更高的解决方案的空间复杂度为 O(1),但此解决方案的空间复杂度为 O(Cn),其中 Cn 是加泰罗尼亚号码。
该代码的时间复杂度与其他高性能解决方案相同,均为 O(Cn)。
I was asked this question in an interview today.
I always skipped this question in Cracking The Coding because I thought it is a silly question for an interview. The interviewer didn't share my opinion though.
Below is the solution that I could come up with in the interview. The interviewer was looking at the more performant method that is already given above. He passed me though for this solution.
The space complexity of other more performant solution is O(1) but for this one is O(Cn), where Cn is Catalan Number.
The time complexity of this code is same as the other high performant solution, which is same as O(Cn).
在 javascript/nodejs 中。
该程序最初是为了回答终极问题,但它恰好可以完美地枚举有效的括号组合。
In javascript / nodejs.
The program was originally meant to answer the Ultimate Question, but it is just perfect to enumerate the valid brackets combinations.
处理此问题的另一个解决方案。
正确的字符串:(){}[]
字符串不正确:([{)]}
Another Solution to handle this issue.
correct string: (){}[]
incorrect string: ([{)]}
在 C# 中
In C#
尝试了一下..还有 C#。
递归利用了这样一个事实:添加的左括号永远不能多于所需的对数,并且添加的右括号永远不能多于左括号。
Took a crack at it.. C# also.
The recursion is taking advantage of the fact that you can never add more opening brackets than the desired number of pairs, and you can never add more closing brackets than opening brackets..
第一个投票答案的 Python 版本。
Python version of the first voted answer.
可能组合的数量是 N 对 C(n) 的加泰罗尼亚数。
这个问题在 joelonsoftware.com 论坛上进行了广泛讨论,包括迭代,递归和迭代/位移解决方案。 那里有一些很酷的东西。
以下是 C# 论坛上建议的快速递归解决方案:
C#
Brackets(3);
The number of possible combinations is the Catalan number of N pairs C(n).
This problem was discussed on the joelonsoftware.com forums pretty exentsively including iterative, recursive and iterative/bitshifting solutions. Some pretty cool stuff there.
Here is a quick recursive solution suggested on the forums in C#:
C#
Brackets(3);
F#:
这是一个解决方案,与我之前的解决方案不同,我相信它可能是正确的。 而且,它的效率更高。
例子:
F#:
Here is a solution that, unlike my previous solution, I believe may be correct. Also, it is more efficient.
Example:
这是另一个 F# 解决方案,它更注重优雅而不是效率,尽管记忆可能会导致性能相对良好的变体。
同样,这只会产生一个包含恰好 n 对括号(而不是最多 n 个)的字符串列表,但很容易将其包装起来。
Here's another F# solution, favoring elegance over efficiency, although memoization would probably lead to a relatively well performing variant.
Again, this only yields a list of those strings with exactly n pairs of parens (rather than at most n), but it's easy to wrap it.
F#:
更新:这个答案是错误的。 我的 N=4 次失误,例如“(())(())”。 (你明白为什么吗?)我很快就会发布一个正确的(而且更有效的)算法。
(对所有投票者感到羞耻,因为没有抓住我!:))
效率低下,但简短而简单。
(请注意,它仅打印“第 n”行;从 1..n 开始循环调用以获取问题所需的输出。)
示例:
F#:
UPDATE: this answer is wrong. My N=4 misses, for example "(())(())". (Do you see why?) I will post a correct (and more efficient) algorithm shortly.
(Shame on all you up-voters, for not catching me! :) )
Inefficient, but short and simple.
(Note that it only prints the 'nth' line; call in a loop from 1..n to get the output asked for by the question.)
Example:
C++ 中的简单解决方案:
输出:
Simple solution in C++:
Output:
该死的 - 每个人都比我先一步,但我有一个很好的工作示例:)
http://www. FiveMinuteargument .com/so-727707
关键是识别规则,实际上非常简单:
Damn - everyone beat me to it, but I have a nice working example :)
http://www.fiveminuteargument.com/so-727707
The key is identifying the rules, which are actually quite simple:
Common Lisp:
这不会打印它们,但会生成所有可能结构的列表。 我的方法和其他人的有点不同。 它将解决方案重构为
brackets(n - 1)
,使它们成为brackets(n)
。 我的解决方案不是尾递归,但可以通过一些工作来实现。代码
Common Lisp:
This doesn't print them, but does produce a list of lists of all the possible structures. My method is a bit different from the others'. It restructures the solutions to
brackets(n - 1)
such that they becomebrackets(n)
. My solution isn't tail recursive, but it could be made so with a little work.Code
这是 C++ 中的解决方案。 我使用的主要想法是,我获取前一个 i 的输出(其中 i 是括号对的数量),并将其作为输入提供给下一个 < em>我。 然后,对于输入中的每个字符串,我们在字符串中的每个位置放置一个括号对。 将新字符串添加到集合中以消除重复项。
Here is a solution in C++. The main idea that I use is that I take the output from the previous i (where i is the number of bracket pairs), and feed that as input to the next i. Then, for each string in the input, we put a bracket pair at each location in the string. New strings are added to a set in order to eliminate duplicates.
一个简单的 F#/OCaml 解决方案:
<代码>
A simple F#/OCaml solution :
基于递归回溯算法的Provider C#版本,希望对您有所帮助。
Provider C# version based on recursive backtracking algorithm, hope it's helpful.
(kin,这类似于具有特征的基于演员模型的线性Python。我没有抽出时间来实现@memo,但上面的方法在没有优化的情况下也能工作)
(kin, which is something like an actor model based linear python with traits. I haven't got round to implementing @memo but the above works without that optimisation)
Haskell:
我试图想出一个优雅的列表单子方式:
Haskell:
I tried to come up with an elegant list monad-y way to this:
为什么不能这么简单,这个想法很简单
bracket(n) -->; '()' + 括号(n-1) 0
'(' + 括号(n-1) + ')' 0
括号(n-1) + '()'
其中 0 是上面的串联操作
why cant this is as simple as this, this idea is quite simple
brackets(n) --> '()' + brackets(n-1) 0
'(' + brackets(n-1) + ')' 0
brackets(n-1) + '()'
where 0 is the concatenation operation above
Groovy 版本基于上述 markt 优雅的 C# 解决方案。 动态检查打开和关闭(信息在输出和参数中重复)以及删除一些无关的逻辑检查。
Groovy version based on markt's elegant c# solution above. Dynamically checking open and close (information was repeated in output and args) as well as removing a couple of extraneous logic checks.
这不是最优雅的解决方案,但这就是我在 C++ (Visual Studio 2008) 中的做法。 利用 STL 集来消除重复项,我只是天真地将 new () 对插入到上一代的每个字符串中的每个字符串索引中,然后递归。
Not the most elegant solution, but this was how I did it in C++ (Visual Studio 2008). Leveraging the STL set to eliminate duplicates, I just naively insert new () pairs into each string index in every string from the previous generation, then recurse.