1. 字符串全排列(不去重)
【题目】输入一个字符串,打印出该字符串中字符的所有排列。例如输入字符串abc,则输出由字符a、b、c所能排列出来的所有字符串abc、acb、bac、bca、cab和cba。
参考:http://www.cnblogs.com/GoAhead/archive/2012/05/30/2526563.html
【分析】采用递归方法:
最外层的循环过程(下面指的是位置交换):
0与0交换abc——内部循环是:1与1交换,输出abc;1与2交换输出acb
0与1交换bac——内部循环是:1与1交换,输出bac;1与2交换输出bca
0与2交换cba——内部循环是:1与1交换,输出cba;1与2交换输出cab
/**
* 创建时间:2014年9月7日下午3:29:42
* 项目名称:Test
* @author Cao Yanfeng 北京大学
* @since JDK 1.6.0_21
* 类说明: 字符全排列,没有去重
*/
public classPermutationTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] array={'a','b','c'};
printPermutation(array, 0, array.length);
}
public static void printPermutation(char[] array,int start,int end) {
if (start==end-1) {
System.out.println(new String(array));
}else {
for (int k = start; k < end; k++) {
swap(array, k, start);
printPermutation(array, start+1, end);
swap(array, k, start);
}
}
}
public static void swap(char[] array,int i,int j) {
if (array[i]!=array[j]) {
array[i]^=array[j];
array[j]^=array[i];
array[i]^=array[j];
}
}
}
2. 字符串全排列(去重)
【参考】http://blog.csdn.net/hackbuteer1/article/details/7462447
【分析】假设是aac
最外层的循环过程(下面指的是位置交换):
0与0交换aac——内部循环是:1与1交换,输出aac;1与2交换输出aca
0与1交换aac——内部循环是:1与1交换,输出aac;1与2交换输出aca
0与2交换caa——内部循环是:1与1交换,输出caa;1与2交换输出caa
所以要阻断上面红色部分,只要交换条件是:待交换的两个数下标相同(比如上面的原地交换,两个数相等)或者待交换的两个数不相等,也就是说上面的0与0仍能交换,0与1、1与2就不能交换了。
下面程序跟上面相比仅仅加了一行语句:if (k==start||array[k]!=array[start])
/
**
* 创建时间:2014年9月7日下午3:29:42
* 项目名称:Test
* @author Cao Yanfeng 北京大学
* @since JDK 1.6.0_21
* 类说明: 字符全排列,去重
*/
public classPermutationTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] array={'a','a','c'};
printPermutation(array, 0, array.length);
}
public static void printPermutation(char[] array,int start,int end) {
if (start==end-1) {
System.out.println(new String(array));
}else {
for (int k = start; k < end; k++) {
if (k==start||array[k]!=array[start]) {
swap(array, k, start);
printPermutation(array, start+1, end);
swap(array, k, start);
}else {
continue;
}
}
}
}
public static void swap(char[] array,int i,int j) {
if (array[i]!=array[j]) {
array[i]^=array[j];
array[j]^=array[i];
array[i]^=array[j];
}
}
}
3. 字符串的所有组合/字符串的所有子集(不去重)
参考:http://blog.csdn.net/xuyuxin8145/article/details/6637692
【分析】a-b-c的组合可以用递归来实现。假设我们想在长度为n的字符串中求m个字符的组合。我们先从头扫描字符串的第一个字符。针对第一个字符,我们有两种选择:一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。这两种选择都很容易用递归实现。
/**
* 创建时间:2014年9月7日下午4:42:33
* 项目名称:Test
* @author Cao Yanfeng 北京大学
* @since JDK 1.6.0_21
* 类说明: 字符串的所有组合,不去重
*/
public classCombination {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
char[] array={'a','b','c'};
combination(array);
}
public static void combination(char[] array) {
if (array==null||array.length==0) {
return;
}
ArrayList<Character>result=newArrayList<Character>();
for (int i = 1; i <=array.length; i++) {
combination_m(array, 0, i, result);
}
}
public static void combination_m (char[] array,int begin,int m,ArrayList<Character>result){
if (m==0) {
System.out.println(result.toString());
return;
}
if (begin==array.length) {
return;
}
/*选择这个元素*/
result.add(array[begin]);
combination_m(array, begin+1, m-1, result);
/*不选择这个元素*/
result.remove((Character)array[begin]);
combination_m(array, begin+1, m, result);
}
}
4. 八皇后问题
【问题】在8×8的国际象棋上摆放八个皇后,使其不能相互攻击,即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。下图中的每个黑色格子表示一个皇后,这就是一种符合条件的摆放方法。请求出总共有多少种摆法。
【分析】columnIndex ={0,1,2,3,4,5,6,7}表示的分别是0~7列的行号,所以不会有位于一行的皇后,也不会有位于一列的皇后。八皇后问题,即获得{0,1,2,3,4,5,6,7}所有排列,排除斜对角线情况即可。斜对角的条件是:(i - j == columnIndex[i] - columnIndex[j]) ||( j - i ==columnIndex[i] - columnIndex[j]),例如{0,1,*,*,*,*,*,*}肯定不行,0与1位于对角线。注意,这里为了在递归过程中统计次数,需要传址调用,所以定义了一个Counter类,不能使用int或Integer。
/**
* 创建时间:2014年9月7日下午9:03:03 项目名称:Test
*
* @author Cao Yanfeng Peking University
* @since JDK 1.6.0_21 类说明:八皇后问题,即获得{0,1,2,3,4,5,6,7}所有排列,排除斜对角线情况即可
* 注意:{0,1,2,3,4,5,6,7}表示的分别是0~7列的行号,所以不会有位于一行的皇后,也不会有位于一列的皇后。
*/
public classEightQueenTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
eightQueue();
}
public static void eightQueue() {
final int queens = 8;
int[] columnIndex = new int[queens];
/* 初始化 */
for (int i = 0; i < columnIndex.length; i++) {
columnIndex[i] = i;
}
Countercounter=new Counter();
counter.setCounter(0);
/*递归的全排列*/
permutation(columnIndex, 0, columnIndex.length,counter);
}
public static void permutation(int[] columnIndex, int start, int end,Counter counter) {
/*只要当前的指针stat指向了最后一个元素,则递归探底*/
if (start == end - 1) {
if (check(columnIndex)) {
counter.setCounter(counter.getCounter()+1);
System.out.print("第"+counter.getCounter()+"种排列:");
for (int i = 0; i < columnIndex.length; i++) {
System.out.print(columnIndex[i]);
}
System.out.println();
}
}else{
for (int k = start; k < end; k++) {
swap(columnIndex, k, start);
permutation(columnIndex, start + 1, end,counter);
swap(columnIndex, k, start);
}
}
}
/*查看该数组是否有两个或以上的元素在斜对角线上*/
public static boolean check(int[] columnIndex) {
for (int i = 0; i < columnIndex.length; i++) {
for (int j = i + 1; j < columnIndex.length; j++) {
if (i - j == columnIndex[i] - columnIndex[j]
||j - i == columnIndex[i] - columnIndex[j]) return false;
}
}
return true;
}
public static void swap(int[] array, int i, int j) {
if (array[i] != array[j]) {
array[i] ^= array[j];
array[j] ^= array[i];
array[i] ^= array[j];
}
}
}
class Counter{
int counter;
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
}
5. 数组array中所有元素都只出现一次,给的一个sum,求array的子集和等于sum的所有子集。
参考:http://blog.csdn.net/hackbuteer1/article/details/7462447
【分析】获得array的所有组合,然后判断即可。对上面的主题3“字符串的所有组合/字符串的所有子集合”进行一些修改即可。
/**
* 创建时间:2014年9月7日下午9:43:24 项目名称:Test
*
* @author Cao Yanfeng Peking University
* @since JDK 1.6.0_21 类说明:数组的所有子集合中,子集合和等于给定数的集合本质是组合问题
*/
public classCombinationTest2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = { 1, 2, 3, 4, 2 };
combination(array, 5);
}
public static void combination(int[] array, int sum) {
if (array == null || array.length == 0) {
return;
}
ArrayList<Integer>result= newArrayList<Integer>();
for (int i = 1; i <= array.length; i++) {
combination_m(array, 0, i, result, sum);
}
}
public static void combination_m(int[] array, int begin, int m,
ArrayList<Integer>result,intsum){
if (m == 0) {
for (Integer integer : result) {
sum -= integer;
}
if (sum == 0) {
System.out.println(result.toString());
}
return;
}
if (begin == array.length) {
return;
}
/* 选择这个元素 */
result.add(array[begin]);
combination_m(array, begin + 1, m - 1, result, sum);
/* 不选择这个元素 */
result.remove((Integer) array[begin]);
combination_m(array, begin + 1, m, result, sum);
}
}
*******************************************************************************
这里遗留了一个问题就是组合有重复的情况,如何去重复。待研究。。。。