程序员

Java/安卓的 排列选择 组合选择算法及Set交集指定过滤

2018-08-23  本文已影响78人  阿敏其人

文/阿敏其人
本文出自“阿敏其人”简书博客,转载请注明出处和链接。


“所谓创意,只是把原有的元素重新组合而已。”美国广告大师詹姆斯。韦伯扬在《创意的生成》一书中如是说。

离开书本,换个角度一看,这个世界也许从来就不存在新的东西,全部就是原有的元素的排列组合罢了。

人类的情感世界太复杂,已知的物理和数学相对靠谱,为了人类整出了 排列数公式 和 组合数公式 。
方便我们排列组合,方便我们研究,方便我们进行“创新”。

排列 和 组合

公式初探

排列数公式:


image.png

组合数公式:


image.png

排列数公式
从n个不同元素中,任取m(m≤n)个元素(被取出的元素各不相同),按照一定的顺序排成一列,叫做从n个不同元素中取出m个元素的一个排列。

组合数公式
组合数公式是指从m个不同元素中,任取n(n≤m)个元素并成一组,叫做从m个不同元素中取出n个元素的一个组合;从m个不同元素中取出n(n≤m)个元素的所有组合的个数,叫做从m个不同元素中取出n个元素的组合数。用符号c(m,n) 表示。

咬文嚼字时间结束,向数学大家致敬的同时,看看如何把公式转成代码:

public class TestOrg {
    public static void main(String[] args) {
        // 排列算法
        long pl = arrangement(3, 2);
         System.out.println("排列:"+pl); // 排列:6
         
         //组合算法
         long zh =  combination(3,2);
         System.out.println("组合:"+zh); // 组合:3
    }
    
    /** 
     * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1 
     * 排列个数
     * @param n 
     * @return 
     */  
    private static long factorial(int n) {  
        return (n > 1) ? n * factorial(n - 1) : 1;  
    }  
      
    /** 
     * 计算排列数,即A(n, m) = n!/(n-m)! 
     * 
     * @param n 
     * @param m 
     * @return 
     */  
    public static long arrangement(int n, int m) {  
        return (n >= m) ? factorial(n) / factorial(n - m) : 0;  
    }  
      
    /** 
     * 计算组合数,即C(n, m) = n!/((n-m)! * m!) 
     * @param n 
     * @param m 
     * @return 
     */  
    public static long combination(int n, int m) {  
        return (n >= m) ? factorial(n) / factorial(n - m) / factorial(m) : 0;  
    } 
}

举个栗子

排列选择 和 组合选择

排列选择demo

public class TestArra{
    public static void main(String[] args) {
          arrangementSelect(new String[] {  
                    "1", "2", "3", "4"  
            }, 2);  
    }
    
    /** 
     * 排列选择(从列表中选择n个排列) 
     * @param dataList 待选列表 
     * @param n 选择个数 
     */  
    public static void arrangementSelect(String[] dataList, int n) {  
        System.out.println(String.format("A(%d, %d) = %d", dataList.length, n, arrangement(dataList.length, n)));  
        arrangementSelect(dataList, new String[n], 0);  
    }  
  
    /** 
     * 排列选择 
     * @param dataList 待选列表 
     * @param resultList 前面(resultIndex-1)个的排列结果 
     * @param resultIndex 选择索引,从0开始 
     */  
    private static void arrangementSelect(String[] dataList, String[] resultList, int resultIndex) {  
        int resultLen = resultList.length;  
        if (resultIndex >= resultLen) { // 全部选择完时,输出排列结果  
            System.out.println(Arrays.asList(resultList));  
            return;  
        }  
  
        // 递归选择下一个  
        for (int i = 0; i < dataList.length; i++) {  
            // 判断待选项是否存在于排列结果中  
            boolean exists = false;  
            for (int j = 0; j < resultIndex; j++) {  
                if (dataList[i].equals(resultList[j])) {  
                    exists = true;  
                    break;  
                }  
            }  
            if (!exists) { // 排列结果不存在该项,才可选择  
                resultList[resultIndex] = dataList[i];  
                arrangementSelect(dataList, resultList, resultIndex + 1);  
            }  
        }  
    } 
    
    /** 
     * 计算排列数,即A(n, m) = n!/(n-m)! 
     * @param n 
     * @param m 
     * @return 
     */  
    public static long arrangement(int n, int m) {  
        return (n >= m) ? factorial(n) / factorial(n - m) : 0;  
    }  
    
    /** 
     * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1 
     * @param n 
     * @return 
     */  
    public static long factorial(int n) {  
        return (n > 1) ? n * factorial(n - 1) : 1;  
    }   
}

输出:

A(4, 2) = 12
[1, 2]
[1, 3]
[1, 4]
[2, 1]
[2, 3]
[2, 4]
[3, 1]
[3, 2]
[3, 4]
[4, 1]
[4, 2]
[4, 3]

组合选择 DEMO

public class TestComb {
    
    public static void main(String[] args) {        
          combinationSelect(new String[] {  
                    "1", "2", "3", "4", "5"  
            }, 2); 
    }
    
    /** 
     * 计算组合数,即C(n, m) = n!/((n-m)! * m!) 
     * @param n 
     * @param m 
     * @return 
     */  
    public static long combination(int n, int m) {  
        return (n >= m) ? factorial(n) / factorial(n - m) / factorial(m) : 0;  
    }
    

    /** 
     * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1 
     * @param n 
     * @return 
     */  
    public static long factorial(int n) {  
        return (n > 1) ? n * factorial(n - 1) : 1;  
    } 
    
    
       /** 
     * 组合选择(从列表中选择n个组合) 
     * @param dataList 待选列表 
     * @param n 选择个数 
     */  
    public static void combinationSelect(String[] dataList, int n) {  
        System.out.println(String.format("C(%d, %d) = %d", dataList.length, n, combination(dataList.length, n)));  
        combinationSelect(dataList, 0, new String[n], 0);  
    }  
  
    /** 
     * 组合选择 
     * @param dataList 待选列表 
     * @param dataIndex 待选开始索引 
     * @param resultList 前面(resultIndex-1)个的组合结果 
     * @param resultIndex 选择索引,从0开始 
     */  
    private static void combinationSelect(String[] dataList, int dataIndex, String[] resultList, int resultIndex) {  
        int resultLen = resultList.length;  
        int resultCount = resultIndex + 1;  
        if (resultCount > resultLen) { // 全部选择完时,输出组合结果  
            System.out.println(Arrays.asList(resultList));  
            return;  
        }  
  
        // 递归选择下一个  
        for (int i = dataIndex; i < dataList.length + resultCount - resultLen; i++) {  
            resultList[resultIndex] = dataList[i];  
            combinationSelect(dataList, i + 1, resultList, resultIndex + 1);  
        }  
    }  
}

输出:

C(5, 2) = 10
[1, 2]
[1, 3]
[1, 4]
[1, 5]
[2, 3]
[2, 4]
[2, 5]
[3, 4]
[3, 5]
[4, 5]

排列选择和组合选择,都是罗列选择结果。
区别是,排列选择是全排列,一个选择内部选择交换了位置,也会认为是一个新的选择。
组合选择里,当一个内部元素的位置发生了变化,会过滤掉,不会认为这是一个新选择。

排列组合乱斗

路飞成长史

public class TestFun {
    public static void main(String[] args) {

        // 组合选择算法
        combinationSelect(new String[] { "路飞打怪", "怪打路飞", "路飞输了开始训练", "路飞赢了开心吃肉"}, 3);

        // 排列选择算法
        arrangementSelect(new String[] {"路飞打怪", "怪打路飞", "路飞输了开始训练", "路飞赢了开心吃肉" }, 3);
    }

    /**
     * 排列选择(从列表中选择n个排列)
     * 
     * @param dataList
     *            待选列表
     * @param n
     *            选择个数
     */
    public static void arrangementSelect(String[] dataList, int n) {
        System.out.println(String.format("A(%d, %d) = %d", dataList.length, n, arrangement(dataList.length, n)));
        arrangementSelect(dataList, new String[n], 0);
    }

    /**
     * 排列选择
     * 
     * @param dataList
     *            待选列表
     * @param resultList
     *            前面(resultIndex-1)个的排列结果
     * @param resultIndex
     *            选择索引,从0开始
     */
    private static void arrangementSelect(String[] dataList, String[] resultList, int resultIndex) {
        int resultLen = resultList.length;
        if (resultIndex >= resultLen) { // 全部选择完时,输出排列结果
            System.out.println(Arrays.asList(resultList));
            return;
        }

        // 递归选择下一个
        for (int i = 0; i < dataList.length; i++) {
            // 判断待选项是否存在于排列结果中
            boolean exists = false;
            for (int j = 0; j < resultIndex; j++) {
                if (dataList[i].equals(resultList[j])) {
                    exists = true;
                    break;
                }
            }
            if (!exists) { // 排列结果不存在该项,才可选择
                resultList[resultIndex] = dataList[i];
                arrangementSelect(dataList, resultList, resultIndex + 1);
            }
        }
    }

    /**
     * 计算排列数,即A(n, m) = n!/(n-m)!
     * 
     * @param n
     * @param m
     * @return
     */
    public static long arrangement(int n, int m) {
        return (n >= m) ? factorial(n) / factorial(n - m) : 0;
    }

    /**
     * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1
     * 
     * @param n
     * @return
     */
    public static long factorial(int n) {
        return (n > 1) ? n * factorial(n - 1) : 1;
    }

    // ===
    /**
     * 计算组合数,即C(n, m) = n!/((n-m)! * m!)
     * 
     * @param n
     * @param m
     * @return
     */
    public static long combination(int n, int m) {
        return (n >= m) ? factorial(n) / factorial(n - m) / factorial(m) : 0;
    }

    // /**
    // * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1
    // * @param n
    // * @return
    // */
    // public static long factorial(int n) {
    // return (n > 1) ? n * factorial(n - 1) : 1;
    // }

    /**
     * 组合选择(从列表中选择n个组合)
     * 
     * @param dataList
     *            待选列表
     * @param n
     *            选择个数
     */
    public static void combinationSelect(String[] dataList, int n) {
        System.out.println(String.format("C(%d, %d) = %d", dataList.length, n, combination(dataList.length, n)));
        combinationSelect(dataList, 0, new String[n], 0);
    }

    /**
     * 组合选择
     * 
     * @param dataList
     *            待选列表
     * @param dataIndex
     *            待选开始索引
     * @param resultList
     *            前面(resultIndex-1)个的组合结果
     * @param resultIndex
     *            选择索引,从0开始
     */
    private static void combinationSelect(String[] dataList, int dataIndex, String[] resultList, int resultIndex) {
        int resultLen = resultList.length;
        int resultCount = resultIndex + 1;
        if (resultCount > resultLen) { // 全部选择完时,输出组合结果
            System.out.println(Arrays.asList(resultList));
            return;
        }

        // 递归选择下一个
        for (int i = dataIndex; i < dataList.length + resultCount - resultLen; i++) {
            resultList[resultIndex] = dataList[i];
            combinationSelect(dataList, i + 1, resultList, resultIndex + 1);
        }
    }
}

输出:

C(4, 3) = 4
[路飞打怪, 怪打路飞, 路飞输了开始训练]
[路飞打怪, 怪打路飞, 路飞赢了开心吃肉]
[路飞打怪, 路飞输了开始训练, 路飞赢了开心吃肉]
[怪打路飞, 路飞输了开始训练, 路飞赢了开心吃肉]
A(4, 3) = 24
[路飞打怪, 怪打路飞, 路飞输了开始训练]
[路飞打怪, 怪打路飞, 路飞赢了开心吃肉]
[路飞打怪, 路飞输了开始训练, 怪打路飞]
[路飞打怪, 路飞输了开始训练, 路飞赢了开心吃肉]
[路飞打怪, 路飞赢了开心吃肉, 怪打路飞]
[路飞打怪, 路飞赢了开心吃肉, 路飞输了开始训练]
[怪打路飞, 路飞打怪, 路飞输了开始训练]
[怪打路飞, 路飞打怪, 路飞赢了开心吃肉]
[怪打路飞, 路飞输了开始训练, 路飞打怪]
[怪打路飞, 路飞输了开始训练, 路飞赢了开心吃肉]
[怪打路飞, 路飞赢了开心吃肉, 路飞打怪]
[怪打路飞, 路飞赢了开心吃肉, 路飞输了开始训练]
[路飞输了开始训练, 路飞打怪, 怪打路飞]
[路飞输了开始训练, 路飞打怪, 路飞赢了开心吃肉]
[路飞输了开始训练, 怪打路飞, 路飞打怪]
[路飞输了开始训练, 怪打路飞, 路飞赢了开心吃肉]
[路飞输了开始训练, 路飞赢了开心吃肉, 路飞打怪]
[路飞输了开始训练, 路飞赢了开心吃肉, 怪打路飞]
[路飞赢了开心吃肉, 路飞打怪, 怪打路飞]
[路飞赢了开心吃肉, 路飞打怪, 路飞输了开始训练]
[路飞赢了开心吃肉, 怪打路飞, 路飞打怪]
[路飞赢了开心吃肉, 怪打路飞, 路飞输了开始训练]
[路飞赢了开心吃肉, 路飞输了开始训练, 路飞打怪]
[路飞赢了开心吃肉, 路飞输了开始训练, 怪打路飞]

mac升级计划演示组合选择

2018款的15寸的mbp,在官方配置的基础上的,提供了几项升级,比如

假设我们选择其中两项目升级,那么显然应该采用组合选择。

public class TestFun {
    public static void main(String[] args) {
        // 排列选择算法
        System.out.println("排列 选择");
        arrangementSelect(new String[] {"升级1T固态", "升级32G内存", "升级i9处理器" }, 2);
    
        
        // 组合选择算法
        System.out.println("组合 选择");
        combinationSelect(new String[] { "升级1T固态", "升级32G内存", "升级i9处理器"}, 2);
}

    /**
     * 排列选择(从列表中选择n个排列)
     * 
     * @param dataList
     *            待选列表
     * @param n
     *            选择个数
     */
    public static void arrangementSelect(String[] dataList, int n) {
        System.out.println(String.format("A(%d, %d) = %d", dataList.length, n, arrangement(dataList.length, n)));
        arrangementSelect(dataList, new String[n], 0);
    }

    /**
     * 排列选择
     * 
     * @param dataList
     *            待选列表
     * @param resultList
     *            前面(resultIndex-1)个的排列结果
     * @param resultIndex
     *            选择索引,从0开始
     */
    private static void arrangementSelect(String[] dataList, String[] resultList, int resultIndex) {
        int resultLen = resultList.length;
        if (resultIndex >= resultLen) { // 全部选择完时,输出排列结果
            System.out.println(Arrays.asList(resultList));
            return;
        }

        // 递归选择下一个
        for (int i = 0; i < dataList.length; i++) {
            // 判断待选项是否存在于排列结果中
            boolean exists = false;
            for (int j = 0; j < resultIndex; j++) {
                if (dataList[i].equals(resultList[j])) {
                    exists = true;
                    break;
                }
            }
            if (!exists) { // 排列结果不存在该项,才可选择
                resultList[resultIndex] = dataList[i];
                arrangementSelect(dataList, resultList, resultIndex + 1);
            }
        }
    }

    /**
     * 计算排列数,即A(n, m) = n!/(n-m)!
     * 
     * @param n
     * @param m
     * @return
     */
    public static long arrangement(int n, int m) {
        return (n >= m) ? factorial(n) / factorial(n - m) : 0;
    }

    /**
     * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1
     * 
     * @param n
     * @return
     */
    public static long factorial(int n) {
        return (n > 1) ? n * factorial(n - 1) : 1;
    }

    // ===
    /**
     * 计算组合数,即C(n, m) = n!/((n-m)! * m!)
     * 
     * @param n
     * @param m
     * @return
     */
    public static long combination(int n, int m) {
        return (n >= m) ? factorial(n) / factorial(n - m) / factorial(m) : 0;
    }

    // /**
    // * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1
    // * @param n
    // * @return
    // */
    // public static long factorial(int n) {
    // return (n > 1) ? n * factorial(n - 1) : 1;
    // }

    /**
     * 组合选择(从列表中选择n个组合)
     * 
     * @param dataList
     *            待选列表
     * @param n
     *            选择个数
     */
    public static void combinationSelect(String[] dataList, int n) {
        System.out.println(String.format("C(%d, %d) = %d", dataList.length, n, combination(dataList.length, n)));
        combinationSelect(dataList, 0, new String[n], 0);
    }

    /**
     * 组合选择
     * 
     * @param dataList
     *            待选列表
     * @param dataIndex
     *            待选开始索引
     * @param resultList
     *            前面(resultIndex-1)个的组合结果
     * @param resultIndex
     *            选择索引,从0开始
     */
    private static void combinationSelect(String[] dataList, int dataIndex, String[] resultList, int resultIndex) {
        int resultLen = resultList.length;
        int resultCount = resultIndex + 1;
        if (resultCount > resultLen) { // 全部选择完时,输出组合结果
            System.out.println(Arrays.asList(resultList));
            return;
        }

        // 递归选择下一个
        for (int i = dataIndex; i < dataList.length + resultCount - resultLen; i++) {
            resultList[resultIndex] = dataList[i];
            combinationSelect(dataList, i + 1, resultList, resultIndex + 1);
        }
    }
}

输出:

排列 选择
A(3, 2) = 6
[升级1T固态, 升级32G内存]
[升级1T固态, 升级i9处理器]
[升级32G内存, 升级1T固态]
[升级32G内存, 升级i9处理器]
[升级i9处理器, 升级1T固态]
[升级i9处理器, 升级32G内存]
组合 选择
C(3, 2) = 3
[升级1T固态, 升级32G内存]
[升级1T固态, 升级i9处理器]
[升级32G内存, 升级i9处理器]

.
.

升级版 单个方向多选,指定过滤元素

在上面的例子中,我们每个升级方向只提供了一个选项,那么是每个方向多个选择呢?

比如,硬盘方向有3个选择:

内存也有三个选择:

那么,按照原有的算法,结果有15种:

C(6, 2) = 15
[SSD-3T版, SSD-2T版]
[SSD-3T版, SSD-1T版]
[SSD-3T版, 内存128G]
[SSD-3T版, 内存32G]
[SSD-3T版, 内存64G]
[SSD-2T版, SSD-1T版]
[SSD-2T版, 内存128G]
[SSD-2T版, 内存32G]
[SSD-2T版, 内存64G]
[SSD-1T版, 内存128G]
[SSD-1T版, 内存32G]
[SSD-1T版, 内存64G]
[内存128G, 内存32G]
[内存128G, 内存64G]
[内存32G, 内存64G]

显然,这不是我们想要的结果。
重复地 加内存和内存之类的是什么鬼?现加一个3T的,再加一个2T的?开什么玩笑。
我们应该做到每一个方向都只能有一个选项出现在最后的筛选结果。

解决办法

1、取出组合选择结果,这步不变
2、筛选数据时,传入原有的方向集,几个小的Set,每个Set代表一个方向
3、将每一个 组合选择 的结果与每个方向的Set做交集运算,如果交集大于2,则放弃。

3步做完,即可。

public class TestFun {
    public static void main(String[] args) {
        // 排列选择算法
        // System.out.println("排列 选择");
        // arrangementSelect(new String[] {"1", "2", "3","4", "5", "6" }, 2);

        // 方向一
        Set<String> set1 = new HashSet<String>();
        set1.add("SSD-1T版");// SSD-1T版
        set1.add("SSD-2T版");// SSD-2T版
        set1.add("SSD-3T版");// SSD-3T版

        // 方向二
        Set<String> set2 = new HashSet<String>();
        set2.add("内存32G"); // 内存32G
        set2.add("内存64G"); // 内存64G
        set2.add("内存128G"); // 内存128G
    
        Set<String> allDataSet = new HashSet<String>();
        allDataSet.addAll(set1);
        allDataSet.addAll(set2);

        // 总的元素
        String[] dataSetAsArray = allDataSet.toArray(new String[allDataSet.size()]);

        List<Set<String>> noPepeatingList = new ArrayList<>();
        noPepeatingList.add(set1);
        noPepeatingList.add(set2);

        // 组合选择算法
        System.out.println("组合 选择");
        // 有多少个方法,就应该有多少种组合。
        // 所以的combinationSelect第二个参数我们传 noPepeatingList.size()
        // 第三个传每个方向原有的元素集,方便后面比较交集过滤
        combinationSelect(dataSetAsArray, noPepeatingList.size(), noPepeatingList);
        //combinationSelect(dataSetAsArray, 2,null);
    }

    /**
     * 排列选择(从列表中选择n个排列)
     * 
     * @param dataList
     *            待选列表
     * @param n
     *            选择个数
     */
    public static void arrangementSelect(String[] dataList, int n) {
        System.out.println(String.format("A(%d, %d) = %d", dataList.length, n, arrangement(dataList.length, n)));
        arrangementSelect(dataList, new String[n], 0);
    }

    /**
     * 排列选择
     * 
     * @param dataList
     *            待选列表
     * @param resultList
     *            前面(resultIndex-1)个的排列结果
     * @param resultIndex
     *            选择索引,从0开始
     */
    private static void arrangementSelect(String[] dataList, String[] resultList, int resultIndex) {
        int resultLen = resultList.length;
        if (resultIndex >= resultLen) { // 全部选择完时,输出排列结果
            System.out.println(Arrays.asList(resultList));

            List<String> strings = Arrays.asList(resultList);
            strings.size();

            return;
        }

        // 递归选择下一个
        for (int i = 0; i < dataList.length; i++) {
            // 判断待选项是否存在于排列结果中
            boolean exists = false;
            for (int j = 0; j < resultIndex; j++) {
                if (dataList[i].equals(resultList[j])) {
                    exists = true;
                    break;
                }
            }
            if (!exists) { // 排列结果不存在该项,才可选择
                resultList[resultIndex] = dataList[i];
                arrangementSelect(dataList, resultList, resultIndex + 1);
            }
        }
    }

    /**
     * 计算排列数,即A(n, m) = n!/(n-m)!
     * 
     * @param n
     * @param m
     * @return
     */
    public static long arrangement(int n, int m) {
        return (n >= m) ? factorial(n) / factorial(n - m) : 0;
    }

    /**
     * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1
     * 
     * @param n
     * @return
     */
    public static long factorial(int n) {
        return (n > 1) ? n * factorial(n - 1) : 1;
    }

    // ===
    /**
     * 计算组合数,即C(n, m) = n!/((n-m)! * m!)
     * 
     * @param n
     * @param m
     * @return
     */
    public static long combination(int n, int m) {
        return (n >= m) ? factorial(n) / factorial(n - m) / factorial(m) : 0;
    }

    // /**
    // * 计算阶乘数,即n! = n * (n-1) * ... * 2 * 1
    // * @param n
    // * @return
    // */
    // public static long factorial(int n) {
    // return (n > 1) ? n * factorial(n - 1) : 1;
    // }

    /**
     * 组合选择(从列表中选择n个组合)
     * 
     * @param dataList
     *            待选列表
     * @param n
     *            选择个数
     */
    public static void combinationSelect(String[] dataList, int n, List<Set<String>> noPepeatingList) {
        System.out.println(String.format("C(%d, %d) = %d", dataList.length, n, combination(dataList.length, n)));
        combinationSelect(dataList, 0, new String[n], 0, noPepeatingList);
    }

    /**
     * 组合选择
     * 
     * @param dataList
     *            待选列表
     * @param dataIndex
     *            待选开始索引
     * @param resultList
     *            前面(resultIndex-1)个的组合结果
     * @param resultIndex
     *            选择索引,从0开始
     * @param noPepeatingList
     *            可变参数,自身不允许重复的数据
     */
    private static void combinationSelect(String[] dataList, int dataIndex, String[] resultList, int resultIndex,
            List<Set<String>> noPepeatingList) {
        int resultLen = resultList.length;
        int resultCount = resultIndex + 1;
        if (resultCount > resultLen) { // 全部选择完时,输出组合结果
            Set<String> staffsSet = new HashSet<String>(Arrays.asList(resultList));
            Set<String> reSultString = new HashSet<String>(Arrays.asList(resultList));
            //List<String> reSultString = Arrays.asList(resultList);
            if (noPepeatingList != null) {
                boolean isContain = false;
                for (Set<String> tempSet : noPepeatingList) {
                    // 交集
                    Set<String> intersectionSet = new HashSet<String>();
                    intersectionSet.addAll(tempSet);
                    // 拿出交集,关键点。
                    intersectionSet.retainAll(reSultString);
                    //如果交集的数量大于2,那么代表和某个子集重复。
                    // 排除数据,不允许存在跟自身原有数据集重复的元素,比如 1,2 在 1,2,3里面,应该排除掉
                    if (intersectionSet.size()>=2) {
                        isContain = true;
                        break;
                    }
                }
                if (!isContain) {
                    System.out.println(reSultString);
                }

            } else {
                System.out.println(reSultString);
            }

            return;
        }

        // 递归选择下一个
        for (int i = dataIndex; i < dataList.length + resultCount - resultLen; i++) {
            resultList[resultIndex] = dataList[i];
            combinationSelect(dataList, i + 1, resultList, resultIndex + 1, noPepeatingList);
        }
    }
}

输出:

组合 选择
C(6, 2) = 15
[SSD-3T版, 内存128G]
[SSD-3T版, 内存32G]
[SSD-3T版, 内存64G]
[SSD-2T版, 内存128G]
[SSD-2T版, 内存32G]
[SSD-2T版, 内存64G]
[SSD-1T版, 内存128G]
[SSD-1T版, 内存32G]
[SSD-1T版, 内存64G]

没错,才是我们想要的结果。

那么如果我们有3个方向呢

试一下:

                // 方向一
        Set<String> set1 = new HashSet<String>();
        set1.add("SSD-1T版");// SSD-1T版
        set1.add("SSD-2T版");// SSD-2T版
        set1.add("SSD-3T版");// SSD-3T版

        // 方向二
        Set<String> set2 = new HashSet<String>();
        set2.add("内存32G"); // 内存32G
        set2.add("内存64G"); // 内存64G
        set2.add("内存128G"); // 内存128G
    
        // 方向三
        Set<String> set3 = new HashSet<>();
        set3.add("处理器i9版"); // 处理器i9
        set3.add("处理器未来i10版"); // 处理器未来i10
        set3.add("处理器未来i11版"); // 处理器未来i11

        Set<String> allDataSet = new HashSet<String>();
        allDataSet.addAll(set1);
        allDataSet.addAll(set2);
        allDataSet.addAll(set3);
        // 总的元素
        String[] dataSetAsArray = allDataSet.toArray(new String[allDataSet.size()]);

        List<Set<String>> noPepeatingList = new ArrayList<>();
        noPepeatingList.add(set1);
        noPepeatingList.add(set2);
        noPepeatingList.add(set3);

        // 组合选择算法
        System.out.println("组合 选择");
        // 有多少个方法,就应该有多少种组合。
        // 所以的combinationSelect第二个参数我们传 noPepeatingList.size()
        // 第三个传每个方向原有的元素集,方便后面比较交集过滤
        combinationSelect(dataSetAsArray, noPepeatingList.size(), noPepeatingList);

输出:

组合 选择
C(9, 3) = 84
[处理器i9版, SSD-3T版, 内存128G]
[处理器i9版, SSD-3T版, 内存32G]
[处理器i9版, SSD-3T版, 内存64G]
[处理器i9版, SSD-2T版, 内存128G]
[处理器i9版, SSD-2T版, 内存32G]
[处理器i9版, SSD-2T版, 内存64G]
[处理器i9版, SSD-1T版, 内存128G]
[处理器i9版, SSD-1T版, 内存32G]
[处理器i9版, SSD-1T版, 内存64G]
[SSD-3T版, 内存128G, 处理器未来i10版]
[SSD-3T版, 内存128G, 处理器未来i11版]
[SSD-3T版, 处理器未来i10版, 内存32G]
[SSD-3T版, 处理器未来i10版, 内存64G]
[SSD-3T版, 内存32G, 处理器未来i11版]
[SSD-3T版, 处理器未来i11版, 内存64G]
[SSD-2T版, 内存128G, 处理器未来i10版]
[SSD-2T版, 内存128G, 处理器未来i11版]
[SSD-2T版, 处理器未来i10版, 内存32G]
[SSD-2T版, 处理器未来i10版, 内存64G]
[SSD-2T版, 内存32G, 处理器未来i11版]
[SSD-2T版, 处理器未来i11版, 内存64G]
[SSD-1T版, 内存128G, 处理器未来i10版]
[SSD-1T版, 内存128G, 处理器未来i11版]
[SSD-1T版, 处理器未来i10版, 内存32G]
[SSD-1T版, 处理器未来i10版, 内存64G]
[SSD-1T版, 内存32G, 处理器未来i11版]
[SSD-1T版, 处理器未来i11版, 内存64G]

没错,27种结果。

每一种结果都是 一个硬盘 + 一个内存 + 一个处理器选择。
绝无重复。

废话终于说完了。

最后,感谢用cgs1999Java实现排列、组合算法

本文完。

上一篇下一篇

猜你喜欢

热点阅读