我在LinkedIn小组here
上看到了这个采访问题总结一下,如果我有一个数组
[1,2,3,4,5]
并输入
3
我需要输出
[1,2,3], [3,2,1], [2,3,1], [2,1,3], [1,3,2], [3,1,2], [2,3,4], [4,3,2],...
没有特别的顺序。
我一直在考虑这个问题。我提出了各种不同的解决方法,但所有方法都使用for循环。
我认为很明显,为了消除循环,它必须是递归的。
我认为我接近于以递归方式对数组进行分区并加入元素,但是由于非常沮丧,我最终需要另一个for循环。
我开始认为这是不可能的(它不可能,否则为什么面试问题?)。
任何想法或链接?可能的输出量应为5PN,其中N为输入。
答案 0 :(得分:1)
以下递归算法将尝试打印{1,..,n}的每个子集。这些子集通过以下双射一对一地具有0到2 ^ n-1之间的数字:对于0到2 ^ n-1之间的整数x,如果x的第一位设置为0,则关联包含1的集合一,如果x的第二位设置为1,则为2,..
void print_all_subsets (int n, int m, int x) {
if (x==pow(2,n)) {
return;
}
else if (x has m bits set to one) {
print the set corresponding to x;
}
print_all_subsets(n,m,x+1);
}
你需要用n = 5(在你的情况下),m = 3(在你的情况下)和x = 0来调用它。
然后你需要实现两个函数“打印对应于x的集合”和“x有m位设置为1”而不用for循环...但这很容易使用再次递归。
但是,我认为这更具挑战性 - 完全消除for循环没有意义,只有以聪明的方式使用它们才有意义。
答案 1 :(得分:1)
你的第一个想法是正确的。每个循环都可以用递归替换。在某些语言(例如Scheme)中,循环实际上是通过递归实现的。所以从任何解决方案开始,继续将循环转换为递归。最终你会完成。
这是一个Python的工作解决方案。
def subsets_of_size (array, size, start=0, prepend=None):
if prepend is None:
prepend = [] # Standard Python precaution with modifiable defaults.
if 0 == size:
return [[] + prepend] # Array with one thing. The + forces a copy.
elif len(array) < start + size:
return [] # Array with no things.
else:
answer = subsets_of_size(array, size, start=start + 1, prepend=prepend)
prepend.append(array[start])
answer = answer + subsets_of_size(array, size-1, start=start + 1, prepend=prepend)
prepend.pop()
return answer
print subsets_of_size([1,2,3,4,5], 3)
答案 2 :(得分:0)
你可以在这里使用递归,每次你调用一个内层时,你给它在数组中的位置,当它返回它时返回一个增加的位置。您已经为此使用了一个while
循环。
伪代码:
int[] input = [1,2,3,4,5];
int level = 3;
int PrintArrayPermutation(int level, int location, string base)
{
if (level == 0)
{
print base + input[location];
return location + 1;
}
while (location <= input.Length)
{
location =
PrintArrayPermutation(level - 1, location, base + input[location]);
}
}
这是我的想法的基本概要。
答案 3 :(得分:0)
我认为解决方案不是使用for-loop,而是有一种使用for循环的最佳方法。
所以,有Heap的算法。以下是wiki http://en.wikipedia.org/wiki/Heap%27s_algorithm
procedure generate(n : integer, A : array of any):
if n = 1 then
output(A)
else
for i := 0; i < n; i += 1 do
generate(n - 1, A)
if n is even then
swap(A[i], A[n - 1])
else
swap(A[0], A[n-1])
end if
end for
end if
答案 4 :(得分:0)
define listPermutations:
input: int p_l , int[] prevP , int atElement , int[] val , int nextElement
output: list
if nextElement > length(val) OR atElement == p_l OR contains(prevP , val[nextElement]
return EMPTY
list result
int[] tmp = copy(prevP)
tmp[atElement] = val[nextElement]
add(result , tmp)
//create the next permutation stub with the last sign different to this sign
//(node with the same parent)
addAll(result , listPermutations(p_l , tmp , atElement , val , nextElement + 1))
//create the next permutation stub with an additional sign
//(child node of the current permutation
addAll(result , listPermutations(p_l , tmp , atElement + 1 , val , 0))
return result
//this will return the permutations for your example input:
listPermutations(3 , new int[3] , 0 , int[]{1 , 2 , 3 , 4 , 5} , 0)
基本思想:给定数量元素的所有排列形成树,其中节点是空排列,节点的所有子节点都有一个额外元素。现在,算法所要做的就是逐级遍历这个树,直到该级别等于所需的排列长度并列出该级别上的所有节点
答案 5 :(得分:0)
以下是JavaScript中的两个递归函数。第一个是组合choose
函数,我们应用第二个函数,置换每个结果(permutator
改编自SO用户,分隔符,在此回答:Permutations in JavaScript?)
function c(n,list){
var result = [];
function _c(p,r){
if (p > list.length)
return
if (r.length == n){
result = result.concat(permutator(r));
} else {
var next = list[p],
_r = r.slice();
_r.push(next)
_c(p+1,_r);
_c(p+1,r);
}
}
_c(0,[])
return result;
}
function permutator(inputArr) {
var results = [];
function permute(arr, memo) {
var cur, memo = memo || [];
function _permute (i,arr,l){
if (i == l)
return
cur = arr.splice(i,1);
if (arr.length === 0){
results.push(memo.concat(cur));
}
permute(arr.slice(), memo.concat(cur));
arr.splice(i, 0, cur[0]);
_permute(i + 1,arr,l)
}
_permute(0,arr,arr.length);
return results;
}
return permute(inputArr);
}
输出:
console.log(c(3,[1,2,3,4,5]))
[[1,2,3],[1,3,2],[2,1,3]...[4,5,3],[5,3,4],[5,4,3]]