在准备即将进行的采访时,我研究了字符串排列问题。 -
问题语句-编写用于生成输入字符串的所有排列的函数。
这是我觉得很好的解决方案。
function getPermutations(string) {
// base case
if (string.length <= 1) {
return new Set(string);
}
var allCharsExceptLast = string.slice(0, -1);
var lastChar = string[string.length - 1];
// recursive call: get all possible permutations for all chars except last
var permutationsOfAllCharsExceptLast = getPermutations(allCharsExceptLast);
// put the last char in all possible positions for each of the above permutations
var permutations = new Set();
permutationsOfAllCharsExceptLast.forEach(function(permutationOfAllCharsExceptLast) {
for (var position = 0; position <= allCharsExceptLast.length; position++) {
var permutation = permutationOfAllCharsExceptLast.slice(0, position) + lastChar + permutationOfAllCharsExceptLast.slice(position);
permutations.add(permutation);
}
});
return permutations;
}
即使我了解解决方案(花了我几次尝试和大约一百万个控制台日志),但递归仍使我感到困惑。有人可以帮我分解时间和空间的复杂性吗?
答案 0 :(得分:3)
让我们考虑一下这个过程。假设我们的字符串长n
个字符。首先,我们必须传递字符串中的每个字符(n
操作),然后为每个字符递归地生成字符串中其他n-1
个字符的排列,从中我们将为每个第二个字符,以递归方式在字符串中生成n-2
个字符的置换,依此类推……直到只剩下1个字符。为了计算总时间复杂度,我们将所有这些项相乘(n * (n-1) * (n-2) * ... * 1 = n!
),以O(n!)的Big-O表示法获得时间复杂度。
考虑为什么我们将它们相乘,我们可以想到一个更简单的问题,如下所示:如果我们有2条裤子和3件衬衫,则要穿多少种衣服。答案很明显是六个,而我们得到这个结果的原因是,对于每件衬衫,裤子都有两种选择,因此我们将衬衫的数量乘以裤子的数量。
我们可以将此示例转换为简单的字符串,例如单词“ cat”。为了获得每个排列,您的代码首先选择一个字符(选择字符的顺序无关紧要,所以我将首先选择“ c”),然后在其余字符串中找到排列,在这种情况下为“ ”。琐碎的是,只有两个置换是“ at”和“ ta”,因此我们将字符串“ atc”和“ tac”添加到总体置换中。接下来,我们取出“ a”,剩下的String是“ ct”,从中排列是“ ct”和“ tc”。因此,我们在整体排列中添加了“ cta”和“ tca”。最后,当我们取出“ t”时做同样的事情,我们最终以“ ca”和“ ac”作为剩余的排列,因此我们在整体排列中添加了“ cat”和“ act”,就完成了。请注意,在这种情况下它们都是唯一的,但是如果字母重复(例如在“哇”中),则您的算法将重复计算,这是可以的,因为这实际上并没有必要解决。
无论如何,希望对您有所帮助,如果还有其他问题,请发表评论。