算法 排列、组合 相关

来源:互联网 发布:linq.js where 编辑:程序博客网 时间:2024/05/17 21:54

字符串的去重全排列

字符串全排列

public class Permutation {    public static void main(String[] args) {        String s = "abc";        permutation(s.toCharArray(), 0);    }   /*        从第一个字符起,挨个与后面每个字符交换。     */    private static void permutation(char[] chars, int start) {        if (chars == null || chars.length == 0) return;        if (start == chars.length - 1) {            System.out.println(chars);        } else {            for (int i = start, length = chars.length; i < length; ++i) {                if (isSwap(chars, start, i)) {                    CommonUtil.swap(chars, i, start);                    permutation(chars, start + 1);                    CommonUtil.swap(chars, i, start);                }            }        }    }    // 与它后面非重复出现的数字交换    private static boolean isSwap(char[] chars, int start, int end) {        for (int i = start; i < end; ++i) {            if (chars[i] == chars[end]) {                return false;            }        }        return true;    }}

八皇后问题

/** * 八皇后问题: * 在8×8的国际象棋上摆放八个皇后,使其不能相互攻击, * 即任意两个皇后不得处在同一行、同一列或者同一对角斜线上。 *  * 求出总共有多少种摆法 */public class EightQueue {    public static void main(String[] args) {        int[] arr = new int[]{0, 1, 2, 3, 4, 5, 6, 7};        sortQueue(arr, 0);    }    /*        在[0,8)的数组上,第i个位置上的数字j表示(第i行,第j列)        0 <= i < 8        0 <= j < 8        即j的全排列,每个i上可以放置[0,8)个数字, 8!        共有8!种方法,排除掉:            处于同一行的 --> 不可能,在设置的时候就有8个位置了            处于同一列的 --> 任意两个i上的数字相同,也是不可能的            任意两个皇后处于同一对角线的 --> 间距相等了     */    private static void sortQueue(int[] arr, int start) {        if (start == arr.length - 1) {            // 过滤            if (isDiagonal(arr)) {                // 是对角线的不输出                return;            }            CommonUtil.printArray(arr);        } else {            for (int i = start, length = arr.length; i < length; ++i) {                CommonUtil.swap(arr, start, i);                sortQueue(arr, start + 1);                CommonUtil.swap(arr, start, i);            }        }    }    private static boolean isDiagonal(int[] arr) {        for (int i = 0, length = arr.length; i < length; ++i) {            for (int j = i + 1; j < length; ++j) {                if (arr[i] - arr[j] == i - j || arr[i] - arr[j] == j - i) {                    return true;                }            }        }        return false;    }}

字符串的组合

/** * <p> * 输入一个字符串,输出该字符串中字符的所有组合。 * 举个例子,如果输入abc,它的组合有a、b、c、ab、ac、bc、abc。 */public class Combination {    /*        2^n -1 个     */    public static void main(String[] args) {        String s = "abc";        combination_bit(s.toCharArray()); // 位运算        combination(s.toCharArray()); // 递归    }  /*        共有 2^n -1 中组合        使用位运算, 001表示a, 010表示b, 100表示c        遍历 [1, 2^n) 个数字,对每个数字进行位运算,找出所有组合        O(2^n) 指数级     */    private static void combination_bit(char[] chars) {        if (chars == null || chars.length == 0) return;        int length = chars.length;        int n = 1 << length;        StringBuilder builder = new StringBuilder();        for (int i = 1; i < n; ++i) {            for (int j = 0; j < length; ++j) {                if ((i & (1 << j)) != 0) { // 001 010 100                    builder.append(chars[j]);                }            }            System.out.println(builder.toString());            builder.delete(0, builder.length());        }    }    /*        在长度为n的字符串中求m个字符的组合, 1 <= m <= n。我们先从头扫描字符串的第一个字符。        针对第一个字符,我们有两种选择:            第一是把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选取m-1个字符;            第二是不把这个字符放到组合中去,接下来我们需要在剩下的n-1个字符中选择m个字符。            这两种选择都很容易用递归实现。     */    private static void combination(char[] chars) {        if (chars == null || chars.length == 0) return;        Stack<Character> stack = new Stack<>();        for (int i = 1, length = chars.length; i <= length; ++i) {            combination(chars, 0, i, stack);        }    }    /*        start指扫描到哪个字符了        number是指几位组合, 1位组合还是m位组合     */    private static void combination(char[] chars, int start, int number, Stack<Character> stack) {        if (number == 0) {            System.out.println(stack.toString());            return;        }        if (start == chars.length) {            return;        }        stack.push(chars[start]);        combination(chars, start + 1, number - 1, stack);        stack.pop();        combination(chars, start + 1, number, stack);    }}

组合习题一

/** * 输入两个整数n和m, * 从数列1,2,3...n中随意取几个数,使其和等于m,要求列出所有的组合。 */public class EqualsMCombination {    public static void main(String[] args) {        // 找出所有组合,输出和为m的组合        findSumIsM(5, 12);        System.out.println();        System.out.println();        // 以和为target寻找        findSumIsM_Simple(5, 12);    }    /*        从最大值开始开始寻找,即从n开始        对于每个n,都有两种选择:            1. 将即计入和m中,在剩下的n-1个数字中继续寻找和为 n-m 的数字            2. 不计算于其中,在剩下的 n-1 个数字中寻找和为m 的数字        终止条件: m==0(找完了)                 n<0 || m<0 (找不到)     */    private static void findSumIsM_Simple(int n, int m) {        if (m > ((1 + n) * n / 2)) {            System.out.println("m太大了");        }        Stack<Integer> stack = new Stack<>();        findIt_Simple(n, m, stack);    }    private static void findIt_Simple(int n, int m, Stack<Integer> stack) {        if (n < 0 || m < 0) {            return;        }        if (m == 0) {            System.out.println(stack);            return;        }        stack.push(n);        findIt_Simple(n - 1, m - n, stack);        stack.pop();        findIt_Simple(n - 1, m, stack);    }    /*        [1,n] 中,获取所有的组合,输出和为m的组合        分两步:            1. 获取所有组合 (就可以使用之前字符串组合的方式)            2. 输出所有和为m的组合        在n个数字中选取m个数字(1<=m<=n), 从1开始遍历数列,针对第一个数字:           将这个数字放到组合中,在剩下的 n-1个 数字中选取m - 1个           不把这个数字放到组合中,在剩下的 n-1 个 数字中选取m个     */    private static void findSumIsM(int n, int m) {        if (m > ((1 + n) * n / 2)) {            System.out.println("没有满足的序列,超过所有数字之和");        }        Stack<Integer> stack = new Stack<>();        for (int i = 1; i <= n; ++i) {            findIt(n, 1, i, stack, m);        }    }    private static void findIt(int n, int start, int number, Stack<Integer> stack, int targetSum) {        if (number == 0) {            int sum = 0;            for (Integer integer : stack) {                sum += integer;            }            if (sum == targetSum) {                System.out.println(stack);            }            return;        }        if (start == n + 1) {            return;        }        stack.push(start);        findIt(n, start + 1, number - 1, stack, targetSum);        stack.pop();        findIt(n, start + 1, number, stack, targetSum);    }}

组合习题二

就是一个特殊情况

/** * Given two integers n and k, * return all possible combinations of k numbers out of 1 ... n. * <p> * 从[1...n]中选取k个数的所有组合 */public class LimitedCombination {    public static void main(String[] args) {        int n = 5;        int k = 2;        Stack<Integer> stack = new Stack<>();        combination(n, 0, k, stack);    }    /*        从n个数中选取k个数,从第一个数开始            1) 选择将其放入组合内,从剩下的 n-1 个数中选取 k-1 个数            2) 不将其放入组合内,从剩下的 n-1 个数中 选取 k 个数     */    private static void combination(int n, int start, int number, Stack<Integer> stack) {        if (number == 0) {            System.out.println(stack);            return;        }        if (start == n + 1) {            return;        }        stack.push(start);        combination(n, start + 1, number - 1, stack);        stack.pop();        combination(n, start + 1, number, stack);    }}




参考:
字符串的全排列和组合算法
July 算法习题 - 字符串4(全排列和全组合)

原创粉丝点击