全排列,从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列
思路1:将一个数组拆分为前、后两部分,对后数组进行遍历,将遍历到的元素添加进前数组,并从后数组中删除,形成两个新的数组,以这两新数组为参数,进行下一步的递归。采用的是深度优先搜索算法
代码:
def dfs(pre, after)
if after.length == 0
yield(pre)
return
end
after.each do |element|
nextPre = pre.clone
nextPre << element
nextAfter = after.clone
nextAfter.delete(element)
dfs(nextPre, nextAfter) do |result|
yield(result)
end
end
end
dfs([], [1, 2, 3, 4, 5]) do |result|
print result
print "\n"
end
思路2:在思路1的基础上进行优化,思路1的代码中,对pre和after的复制产生了额外的时间和空间开销,于是可以考虑将pre改为栈结构,after改为链表结构(在ruby中全都以数组来实现),在对after的遍历中,直接将after中的元素弹出给pre,递归结束后再将pre的头元素弹回到after的原位置,再进行下一次迭代:
def dfs(pre, after)
if after.length == 0
yield(pre)
return
end
(0..after.length-1).each do |i|
pre << after.delete_at(i)
dfs(pre, after) do |result|
yield(result)
end
after[i, 0] = pre.pop
end
end
思路3:使用广度优先搜索算法,建立一个队列,队列中的元素为哈希表,哈希表由pre和after两个数组组成,队列初始只有一个哈希表,就是pre是空数组,after是原始数组,然后对after进行遍历,遍历中的操作跟前面类似,从after中弹出元素到pre,然后把新的pre和after装进一个新的哈希表,添加到队列末尾,遍历结束后,将队列头弹出,直到队列头的after长度为0,即表示全排列完成:
def bfs(queue)
while queue.first['after'].length > 0
pre = queue.first['pre']
after = queue.first['after']
(0..after.length-1).each do |i|
nextPre = pre.clone
nextAfter = after.clone
nextPre << nextAfter.delete_at(i)
queue << Hash['pre' => nextPre, 'after' => nextAfter]
end
queue.shift
end
yield(queue)
end