我们将使用分治法实现一个全排列算法。先来看一下算法实现后的效果:
算法描述
分治法求解问题分为三个步骤:
- 分解:将问题分为若干个子问题。
- 解决:递归地求解每个子问题。
- 合并:将每个子问题的解合并成为整个问题的解。
现在我们需要求具有n个元素的数组A的全排列。例如:大小为3的数组A=[a,b,c] (为方便起见,我把引号全都省略了,其实应该是A=['a','b','c']。下同),它的全排列为:
[[a,b,c],
[a,c,b],
[b,a,c],
[b,c,a],
[c,a,b],
[c,b,a]]
这是一个大小为 n!*n 的二维数组。
使用分治算法求解全排列的过程如下
- 分解:将数组分为子数组 A[1..k-1] 和一个元素 A[k]。 (1≤k≤n)
- 解决:递归地求解每个子数组 A[1..k-1] 的全排列,直至子数组A[1..k-1]为空时结束递归。
- 合并:将上一步的结果---A[1..k-1]的全排列(一个二维数组)与元素A[k]合并,得出A[1..k]的全排列。例如:
[[]] 与 a 合并得到 [[a]]
[[a]] 与 b 合并得到 [[a,b], [b,a]]
[[a,b],[b,a]] 与 c 合并得到 [[a,b,c],[a,c,b],[c,a,b],[b,c,a],[c,a,b],[c,b,a]]
看下面的图示会更直观一些
1. 分解过程
2. 合并过程
源代码
下面是ruby的源代码(文件名“permutation.rb”)
源代码用于输出二维数组的“pp_extension”可以看我的这篇文章让ruby以矩阵的样式输出二维数组
源代码如下(文件名"pp_extension.rb")
运行时间
算法运行时间 T(n) = T(n-1) + Θ(n2) = Θ(n3)
注 本文并不是从教科书上抄下来的,而是我闭门造车的结果,所以很可能有不正之处,请不吝赐教。
['a','b','c'].permutation #=> [["a", "b", "c"],
# ["a", "c", "b"],
# ["b", "a", "c"],
# ["b", "c", "a"],
# ["c", "a", "b"],
# ["c", "b", "a"]]
# ["a", "c", "b"],
# ["b", "a", "c"],
# ["b", "c", "a"],
# ["c", "a", "b"],
# ["c", "b", "a"]]
算法描述
分治法求解问题分为三个步骤:
- 分解:将问题分为若干个子问题。
- 解决:递归地求解每个子问题。
- 合并:将每个子问题的解合并成为整个问题的解。
现在我们需要求具有n个元素的数组A的全排列。例如:大小为3的数组A=[a,b,c] (为方便起见,我把引号全都省略了,其实应该是A=['a','b','c']。下同),它的全排列为:
[[a,b,c],
[a,c,b],
[b,a,c],
[b,c,a],
[c,a,b],
[c,b,a]]
这是一个大小为 n!*n 的二维数组。
使用分治算法求解全排列的过程如下
- 分解:将数组分为子数组 A[1..k-1] 和一个元素 A[k]。 (1≤k≤n)
- 解决:递归地求解每个子数组 A[1..k-1] 的全排列,直至子数组A[1..k-1]为空时结束递归。
- 合并:将上一步的结果---A[1..k-1]的全排列(一个二维数组)与元素A[k]合并,得出A[1..k]的全排列。例如:
[[]] 与 a 合并得到 [[a]]
[[a]] 与 b 合并得到 [[a,b], [b,a]]
[[a,b],[b,a]] 与 c 合并得到 [[a,b,c],[a,c,b],[c,a,b],[b,c,a],[c,a,b],[c,b,a]]
看下面的图示会更直观一些
1. 分解过程
[a,b,c]
/ \
[a,b] c
/ \
[a] b
/ \
[] a
/ \
[a,b] c
/ \
[a] b
/ \
[] a
2. 合并过程
[] a
\ /
[[a]] b
\ /
[[a,b],[b,a]] c
\ /
[[a,b,c],
[a,c,b],
[c,a,b],
[b,a,c],
[b,c,a],
[c,b,a]]
\ /
[[a]] b
\ /
[[a,b],[b,a]] c
\ /
[[a,b,c],
[a,c,b],
[c,a,b],
[b,a,c],
[b,c,a],
[c,b,a]]
源代码
下面是ruby的源代码(文件名“permutation.rb”)
class Array
# Returns permutation(a new two-dimentional array) of self.
# Example
# - [].permutation #=> [[]]
# - ['A'].permutation #=> [['A']]
# - ['A','B'].permutation #=> [['A','B'],['B','A']]
# - ['A','B','C'].permutation #=> [['A','B','C'],
# ['A','C','B'],
# ['B','A','C'],
# ['B','C','A'],
# ['C','A','B'],
# ['C','B','A']]
def permutation()
permutation_i(self.length-1).sort!
end
private
def permutation_i(i)
if i> 0
return Array.merge_permutation(permutation_i(i-1), self[i])
else
return Array.merge_permutation([[]], self[i])
end
end
# Example
# - Array.merge_permutation([[]], 'A') #=> [['A']]
# - Array.merge_permutation([['A']], 'B') #=> [['B','A'],['A','B']]
# - Array.merge_permutation([['B','A'],['A','B']], 'C') #=> [['C','B','A'],
# ['B','C','A'],
# ['B','A','C'],
# ['C','B','A'],
# ['A','C','B'],
# ['A','B','C']]
def Array.merge_permutation(src, item)
result = Array.new
src.each do |each_array|
result += Array.item_permutation(each_array, item)
end
return result
end
# Returns a new two-dimentional array. Inserts "item" in each pertential place in "src".
# Example
# - Array.item_permutation([], 'A') #=> [['A']]
# - Array.item_permutation(['A'], 'B') #=> [['B','A'], ['A','B']]
# - Array.item_permutation(['A','B'], 'C') #=> [['C','A','B'], ['A','C','B'], 'A','B','C']]
def Array.item_permutation(src, item)
result = Array.new
(0..src.length).each do |i|
new_array = src.collect
new_array.insert(i, item)
result << new_array
end
return result
end
end
require 'pp_extension'
pp(['a','b','c'].permutation)
# Returns permutation(a new two-dimentional array) of self.
# Example
# - [].permutation #=> [[]]
# - ['A'].permutation #=> [['A']]
# - ['A','B'].permutation #=> [['A','B'],['B','A']]
# - ['A','B','C'].permutation #=> [['A','B','C'],
# ['A','C','B'],
# ['B','A','C'],
# ['B','C','A'],
# ['C','A','B'],
# ['C','B','A']]
def permutation()
permutation_i(self.length-1).sort!
end
private
def permutation_i(i)
if i> 0
return Array.merge_permutation(permutation_i(i-1), self[i])
else
return Array.merge_permutation([[]], self[i])
end
end
# Example
# - Array.merge_permutation([[]], 'A') #=> [['A']]
# - Array.merge_permutation([['A']], 'B') #=> [['B','A'],['A','B']]
# - Array.merge_permutation([['B','A'],['A','B']], 'C') #=> [['C','B','A'],
# ['B','C','A'],
# ['B','A','C'],
# ['C','B','A'],
# ['A','C','B'],
# ['A','B','C']]
def Array.merge_permutation(src, item)
result = Array.new
src.each do |each_array|
result += Array.item_permutation(each_array, item)
end
return result
end
# Returns a new two-dimentional array. Inserts "item" in each pertential place in "src".
# Example
# - Array.item_permutation([], 'A') #=> [['A']]
# - Array.item_permutation(['A'], 'B') #=> [['B','A'], ['A','B']]
# - Array.item_permutation(['A','B'], 'C') #=> [['C','A','B'], ['A','C','B'], 'A','B','C']]
def Array.item_permutation(src, item)
result = Array.new
(0..src.length).each do |i|
new_array = src.collect
new_array.insert(i, item)
result << new_array
end
return result
end
end
require 'pp_extension'
pp(['a','b','c'].permutation)
源代码用于输出二维数组的“pp_extension”可以看我的这篇文章让ruby以矩阵的样式输出二维数组
源代码如下(文件名"pp_extension.rb")
require 'pp'
# Outputs two-dimension array like matrix
class Array
def pretty_print(q)
q.group(1, '[', ']') {
q.seplist(self) {|v|
q.current_group.break if v.is_a?(Array) && !q.current_group.first? # added by me
q.pp v
}
}
end
end
# Outputs two-dimension array like matrix
class Array
def pretty_print(q)
q.group(1, '[', ']') {
q.seplist(self) {|v|
q.current_group.break if v.is_a?(Array) && !q.current_group.first? # added by me
q.pp v
}
}
end
end
运行时间
算法运行时间 T(n) = T(n-1) + Θ(n2) = Θ(n3)
注 本文并不是从教科书上抄下来的,而是我闭门造车的结果,所以很可能有不正之处,请不吝赐教。
分类:
算法学习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?