全排列
所谓全排列就是根据输入字符打印出所有字符的排列方式(分次序)。例如输入abc,所有排序的结果有,abc,cba,bac,cab,acb,bca 共6种情况。对于全排列,如果用循环的方法,需要O(n^n)的时间复杂度,其中包含大量的重复序列,需要做判断排除。显然不是一个好方法。
观察abc
、acb
、cba
三者的关系,可以看出,后两者是abc
的第一位a
与bc
交换所得。因此我们可以得出结论
全排列就是从第一个元素起分别与它后面的元素交换所形成的集体,用递归的方法实现,时间复杂度为O(n!)
校验:全排列的总次数为f(n)=n!
package pailie;
public class Permutation {
int count = 0;
public void permutation(char[] cs, int index) {
if (index > cs.length)
return;
if (index == cs.length) { // 避免重复打印,也可以放进set中解决
System.out.println(new String(cs));
count++;
}
for (int i = index; i < cs.length; i++) {
swap(cs, index, i);
permutation(cs, index + 1);
swap(cs, index, i); // 再次交换,保持原状
}
}
private void swap(char[] cs, int index, int target) {
char tmp = cs[index];
cs[index] = cs[target];
cs[target] = tmp;
}
public static void main(String[] args) {
char[] cs = new char[] { 'a', 'b', 'c','d' };
Permutation per = new Permutation();
per.permutation(cs, 0);
System.out.println("方法总数:" + per.count);
}
}
全组合
从m个元素中任取n个的元素为一个组合。全组合是从m个元素中任取x(0<x<=m)
个元素所有的可能性。比如abc的全组合有,a,b,c,ab,ac,bc,abc七种。
对于n个元素的集合,最终组合的结果数是2^n-1
。可以这样思考,每个元素都可以用0表示不取,用1表示取该元素,每个元素都有2种可能,总的可能数有2^n
,而一个都不取没有意义,所以要减1.
一位代表一个元素(字符),使用移位运算。
package pailie;
public class Combination {
void combination(String s) {
char[] strs = s.toCharArray();
int n = s.length();
int nbit = 1 << n;
for (int i = 0; i < nbit; i++) {
for (int j = 0; j < n; j++) {
int tmp = 1 << j; // 由0到n右移位
if ((tmp & i) != 0) { // 与运算,同为1时才会是1
System.out.print(strs[j]);
}
}
System.out.println();
}
System.out.println("结果数为:" + (nbit - 1));
}
public static void main(String[] args) {
new Combination().combination("cgz");
}
}