字符串的排列与组合

字符串全排列

求字符串的排列可以把字符串看成两部分:第一部分为它的第一个字符,第二部分是后面的所有字符。
求字符串的全排列的时候,可以用两步完成:首先求所有可能出现在第一个位置的字符,即把第一个字符与后面的所有字符交换。第二步固定第一个字符,求后面所有字符的排列。从中可以看出是典型的递归思路。 
/**
 * 字符串的全排列
 */
public class Permutation {

    @Test
    public void testCase() {
        permutation("abcc");
    }

    /**
     * 求字符串的全排列
     *
     * @param str
     */
    public void permutation(String str) {
        permutation(str.toCharArray(), 0);
    }

    /**
     * 求begin位置开始字符数组的排列
     *
     * @param strArr 字符数组
     * @param begin  begin位置
     */
    private void permutation(char[] strArr, int begin) {
        if (begin == strArr.length - 1) {//begin等于最后一个字符位置结束递归
            System.out.println(Arrays.toString(strArr));
        } else {
            for (int i = begin; i < strArr.length; i++) {
                //1.把第一个字符与后边的所有字符交换
                swap(strArr, begin, i);
                //2.固定第一个字符,对后边的所有字符全排列
                permutation(strArr, begin + 1);
                //3.把交换到后边的字符交换回来
                swap(strArr, begin, i);
            }
        }
    }

    /**
     * 交换数组中k1与k2位置的两个元素
     *
     * @param arr
     * @param k1
     * @param k2
     */
    private void swap(char[] arr, int k1, int k2) {
        char temp = arr[k1];
        arr[k1] = arr[k2];
        arr[k2] = temp;
    }
}

上述的代码在字符不重复的情况下是正常的,如果出现重复字符例如"abcc",就会输出重复的排列情况。可以通过判断当前准备交换的字符,在begin字符前面的子字符串中是否出现过了,若出现了,就不交换,若没出现就交换。修改下上述方法。

/**
 * 字符串的全排列
 */
public class Permutation {

    @Test
    public void testCase() {
        permutation("abcc");
    }

    /**
     * 求字符串的全排列
     *
     * @param str
     */
    public void permutation(String str) {
        permutation(str.toCharArray(), 0);
    }

    /**
     * 求begin位置开始字符数组的排列
     *
     * @param strArr 字符数组
     * @param begin  begin位置
     */
    private void permutation(char[] strArr, int begin) {
        if (begin == strArr.length - 1) {//begin等于最后一个字符位置结束递归
            System.out.println(Arrays.toString(strArr));
        } else {
            for (int i = begin; i < strArr.length; i++) {
                if (!isExist(strArr, begin, i)) {
                    //1.把第一个字符与后边的所有字符交换
                    swap(strArr, begin, i);
                    //2.固定第一个字符,对后边的所有字符全排列
                    permutation(strArr, begin + 1);
                    //3.把交换到后边的字符交换回来
                    swap(strArr, begin, i);
                }
            }
        }
    }

    /**
     * isExist判断j位置的字符是否已经在list[0]~list[j-1]中出现过了
     * list是含重复字符的数组,i是指示当前位置的游标,j是要判断的字符的位置
     */
    public boolean isExist(char[] arr, int i, int j) {
        for (int k = i; k < j; k++) {
            if (arr[j] == arr[k]) {
                return true;
            }
        }
        return false;
    }

    /**
     * 交换数组中k1与k2位置的两个元素
     *
     * @param arr
     * @param k1
     * @param k2
     */
    private void swap(char[] arr, int k1, int k2) {
        char temp = arr[k1];
        arr[k1] = arr[k2];
        arr[k2] = temp;
    }
}

字符串组合

求n个字符中m个字符的组合的时候,可以把这n个字符分成两部分:第一个字符和其余的所有字符。如果组合里包含第一个字符,则下一步在剩余的字符里选取m-1个字符;如果组合里不包含第一个字符,则下一步在剩余的n-1个字符里选取m个字符,从中可以看出又是个递归的过程。

/**
 * 求字符串的组合
 */
public class Combination {

    @Test
    public void testCase() {
        combination("abc");
    }

    /**
     * 打印输入字符串包含的所有字符的所有组合
     *
     * @param str
     */
    public void combination(String str) {
        char[] arr = str.toCharArray();
        for (int i = 1; i <= arr.length; i++) {
            combination(arr, 0, i);
        }
    }

    /**
     * 存储组合的容器
     */
    private Stack<Character> stack = new Stack<>();

    /**
     * 从begin位置开始,选取num个字符
     *
     * @param strArr
     * @param begin
     * @param num
     */
    private void combination(char[] strArr, int begin, int num) {
        if (num == 0) {
            System.out.println(stack);
            return;
        }
        if (begin >= strArr.length) {
            return;
        } else {
            //把第一个字符放入组合中,在剩余的字符中选取num-1个字符
            stack.push(strArr[begin]);
            combination(strArr, begin + 1, num - 1);
            //组合里不包含第一个字符,则下一步在剩余的字符中选取num个字符
            stack.pop();
            combination(strArr, begin + 1, num);
        }
    }
}

1、八皇后问题:在8*8的国际象棋上摆放八个皇后,使其任意两个皇后不能在同一行,同一列或者同一对角线上,求符合的摆法。
2、把8个数字分别放到正方体的8个顶点上,使正方体三组相对面上的四个定点的和都相等
上述两个问题都可以使8个数字全排列,分别进行判断是否符合上述条件 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值