字符串的排列与组合及八皇后等其他相关问题

 

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

01交换aac——内部循环是:11交换,输出aac12交换输出aca

0与2交换caa——内部循环是:1与1交换,输出caa;12交换输出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);
    }
}


*******************************************************************************

这里遗留了一个问题就是组合有重复的情况,如何去重复。待研究。。。。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值