排列
December 7, 2021將一組數字、字母或符號進行排列,以得到不同的排列順序,例如 1 2 3 這三個數的排列有 1 2 3、1 3 2、2 1 3、2 3 1、3 1 2、3 2 1。
解法思路
如果是 1 2,將兩個旋轉就得到新排列 2 1。如果是 1 2 3,想得到 2 開頭的排列,可以從 1 2 3 將 2 拿到前頭得到 2 1 3,想得到 3 開頭的排列,可以將 3 拿到前頭,得到 3 開頭的 3 1 2。
可以觀察到,從 1 2 3 得到 2 1 3,其實就是將開頭的 1 2 旋轉,從 1 2 3 得到 3 1 2,就是將 1 2 3 旋轉。如果這樣的旋轉可以得到新排列,那麼對於 1 2 3、2 1 3、3 1 2 的尾數列 2 3、1 3、1 2 也做相同旋轉處理,就可以得到尾數列的新排列。也就是:
- 以上紅色部份表示對整個數列旋轉處理,底線表示對尾數列旋轉處理,也就是對尾數列進行相同動作,這在程式上就是遞迴處理。因此對於任意長度的符號數列排列時,可對傳入數列旋轉處理,旋轉間隔一開始是 0,逐步增加,對旋轉過後的每個數列之尾數列再排列。例如對於 1 2 3 4:
- 1 2 3 4 -> 旋轉 1 為 1,遞迴處理 2 3 4
- 2 1 3 4 -> 旋轉 1 2 為 2 1,遞迴處理 1 3 4
- 3 1 2 4 -> 旋轉 1 2 3 為 3 1 2,遞迴處理 1 2 4
- 4 1 2 3 -> 旋轉 1 2 3 4 為 4 1 2 3,遞迴處理 1 2 3
程式實作
#include <stdio.h>
#include <stdlib.h>
#define N 4
void perm(int*, int, void (*)(int*));
void rotate(int*, int, int);
void copy(int*, int*);
void print(int*);
int main(void) {
int num[N] = {1, 2, 3, 4};
perm(num, 0, print);
return 0;
}
void perm(int* num, int i, void (*take)(int*)) {
if(i < N) {
int j;
for(j = i; j < N; j++) {
int to[N];
copy(num, to);
rotate(to, i, j);
perm(to, i + 1, take);
}
} else { take(num); }
}
void rotate(int* num, int i, int j) {
int tmp = num[j];
int k;
for(k = j; k > i; k--) {
num[k] = num[k - 1];
}
num[i] = tmp;
}
void copy(int* from, int* to) {
int i;
for(i = 0; i < N; i++) {
to[i] = from[i];
}
}
void print(int* num) {
int i;
for(i = 0; i < N; i++) {
printf("%d ", num[i]);
}
printf("\n");
}
import java.util.*;
public class Permutation {
public static <T> List<T> rotatedTo(int i, List<T> list) {
List<T> rotated = new ArrayList<>();
rotated.add(list.get(i));
rotated.addAll(list.subList(0, i));
rotated.addAll(list.subList(i + 1, list.size()));
return rotated;
}
public static <T> List<List<T>> allRotated(List<T> list) {
List<List<T>> allRotated = new ArrayList<>();
for(int i = 0; i < list.size(); i++) {
allRotated.add(rotatedTo(i, list));
}
return allRotated;
}
public static <T> List<List<T>> perm(List<T> list) {
List<List<T>> pls = new ArrayList<>();
if(list.isEmpty()) {
pls.add(new ArrayList<T>());
} else {
for(List<T> lt : allRotated(list)) {
for(List<T> tailPl : perm(lt.subList(1, lt.size()))) {
List<T> pl = new ArrayList<>();
pl.add(lt.get(0));
pl.addAll(tailPl);
pls.add(pl);
}
}
}
return pls;
}
public static void main(String[] args) {
for(List<Integer> pl : perm(Arrays.asList(1, 2, 3, 4))) {
System.out.println(pl);
}
}
}
from functools import reduce
def allRotated(list):
def rotatedTo(i):
return [list[i]] + list[0:i] + list[i + 1:]
return [rotatedTo(i) for i in range(len(list))]
def perm(list):
if list == []:
return [[]]
else:
lts = allRotated(list)
return reduce(lambda a, b: a + b,
[[[lt[0]] + pl for pl in perm(lt[1:])] for lt in lts])
for list in perm([1, 2, 3, 4]):
print(list)
def allRotated[T](list: List[T]) = {
def rotatedTo(i: Int) = {
list(i) :: (list.take(i) ++ list.drop(i + 1))
}
(for(i <- 0 until list.size) yield rotatedTo(i)).toList
}
def perm[T](list: List[T]): List[List[T]] = {
if(list.isEmpty) List(Nil)
else {
val lts = allRotated(list)
(for(lt <- lts) yield
(for(pl <- perm(lt.tail)) yield lt.head :: pl)).reduce(_ ++ _)
}
}
perm(List(1, 2, 3, 4)).foreach(println)
def allRotated(list)
rotatedTo = ->(i) {
[list[i]] + list.take(i) + list.drop(i + 1)
}
(0...list.size).map {|i| rotatedTo.call(i)}
end
def perm(list)
if list == []
[[]]
else
lts = allRotated(list)
lts.map {|lt|
perm(lt.drop(1)).map {|pl| [lt[0]] + pl}
}.reduce(:+)
end
end
perm([1, 2, 3, 4]).each do |list|
printf("%s\n", list)
end
function allRotated(list) {
function rotatedTo(i) {
var rotated = [];
rotated.push(list[i]);
return rotated.concat(list.slice(0, i))
.concat(list.slice(i + 1, list.length));
}
var all = [];
for(var i = 0; i < list.length; i++) {
all.push(rotatedTo(i));
}
return all;
}
function perm(list) {
var pls = [];
if(list.length == 0) {
pls.push([]);
} else {
allRotated(list).forEach(function(lt) {
perm(lt.slice(1, lt.length)).forEach(function(tailPl) {
var pl = [];
pl.push(lt[0]);
pls.push(pl.concat(tailPl));
});
});
}
return pls;
}
perm([1, 2, 3, 4]).forEach(function(lt) {
print(lt);
});
allRotated list = [rotatedTo i | i <- [0..(length list) - 1]]
where rotatedTo i = (list !! i) :
((take i list) ++ (drop (i + 1) list))
perm list =
if list == [] then [[]]
else
let lts = allRotated list
in foldl1 (++) [[head lt : pl | pl <- perm $ tail lt] | lt <- lts]
main = sequence [print lt | lt <- perm [1, 2, 3, 4]]