递归穷举&进制转换

递归穷举

概念

穷举是从指定的一组数据m中,选取出n个,然后对选取出的数据做加工计算(如求和、求可能结果等),根据选取数据的规则可以分为三种情况:

  1. 可重复的选取,有m^n种可能性,即第1位可以从m个数据中选一个,第2位依然可以从m个数据中选一个,…,第n位依然可以从m个数据中选一个,总的可能性为:m*m*…*m 。(n个m相乘)
  2. 排列选取,有m!/(m-n)!种可能性,即第1位可以从m个数据中选一个,第2位可以从m-1个数据中选一个,…,第n位可以从m-n+1个数据中选一个,总的可能性为:m*(m-1)*…*(m-n+1)。(是从m个数据中,选n,考虑顺序的情况下的可能性)
  3. 组合,m中选出n,不考虑顺序,可能的选法。有m!/[(m-n)!*n!]种可能性,即第1位可以从m-n+1个数据中选一个,第2位依然可以从第一个选择的数据后的位置选择一个数据(因为第1个选择的数据位置前的数据,已经被之前的穷举覆盖到),…,第n位可以从n-1个数据中选一个,此为算法考虑的思路。考虑总的可能性时,需要转换思路:排序是考虑顺序的一种数据选取方式,通过排序得到的可能性,存在有同一组数据的不同排列方式,若有n个数据,重复的方式为n!,因此,组合的可能性为排序可能性除以重复的排列方式,即总的可能性为:m!/[(m-n)!*n!]。(是从m个数据中,选n,不考虑顺序的情况下的可能性,在考虑顺序的情况下,把重复的数据去掉存在的可能性)

算法

如果仅需要知道存在的可能性个数,通过上面的计算公式,即可计算;下面是假设要找到所有的可能性数据列表,给出的算法。
上述的可重复穷举、排列、组合。均是从m个元素中选取n个,区别在于每次选取的数据的范围不同,可重复选取每次都能从m个中选,排列只能从未选的数据中选择,组合则是从当前选择数据的后一个开始选择。可以通过递归的方式实现,循环体为从未选列表中选择一个数据,添加到已选列表,递归的终止条件未已经选择出n个元素(递归的深度递减为0),递归方法的入参有三个:

  1. 未选的数据列表:List noSelect
  2. 已选择的数据列表:List select
  3. 当前剩余的递归次数: int deep;(深度将为0或者当前处理的深度为1时,则为最后一次递归)

java代码实现

	/**
	* 测试主方法
	*/
	public static void main(String[] args) {
		List<String> noSelect = Arrays.asList("1", "2", "3");
        List<String> select = new ArrayList<>();
	//        chongFu_QIONGJU(noSelect, select, 2);
	//        paiLie_QIONGJU(noSelect, select, 2);
	        zuHe_QIONGJU(noSelect, select, 2);
	}

	/**
     * 允许重复的可能性
     * @param noSelect 未选中的列表
     * @param select 选中的列表
     * @param deep 递归深度
     */
    private static void chongFu_QIONGJU(List<String> noSelect,List<String> select,int deep) {
        for (String one: noSelect) {
            List<String> newSelect = new ArrayList<>();
            copyList(select, newSelect, 0, -1);
            newSelect.add(one);
            int temp = deep -1;
            if (0 == temp) {
                System.out.println(newSelect);
            } else {
                chongFu_QIONGJU(noSelect, newSelect, temp);
            }
        }
    }
    
    /**
     * 排列穷举算法
     */
    private static void paiLie_QIONGJU(List<String> noSelect,List<String> select,int deep) {
        for (int i = 0; i < noSelect.size(); i++) {
            String one = noSelect.get(i);
            List<String> newSelect = new ArrayList<>();
            copyList(select, newSelect, 0, -1);
            newSelect.add(one);
            int temp = deep -1;
            if (0 == temp) {
                System.out.println(newSelect);
            } else {
                List<String> newNoSelect = new ArrayList<>();
                copyList(noSelect, newNoSelect, 0, i);
                paiLie_QIONGJU(newNoSelect, newSelect, temp);
            }
        }
    }
    
    /**
     * 组合穷举算法
     */
    private static void zuHe_QIONGJU(List<String> noSelect,List<String> select,int deep) {
        for (int i = 0; i < noSelect.size()-deep+1; i++) {
            String one = noSelect.get(i);
            List<String> newSelect = new ArrayList<>();
            copyList(select, newSelect, 0, -1);
            newSelect.add(one);
            int temp = deep -1;
            if (0 == temp) {
                System.out.println(newSelect);
            } else {
                List<String> newNoSelect = new ArrayList<>();
                copyList(noSelect, newNoSelect, i, i);
                zuHe_QIONGJU(newNoSelect, newSelect, temp);
            }
        }
    }
	
	/**
     * 拷贝满足条件的集合
     * @param source
     * @param target
     * @param pos
     * @param noCopyPos
     */
    public static void copyList(List<String> source, List<String> target, int pos , int noCopyPos) {
        for (int i= pos ; i< source.size(); i++) {
            if(i != noCopyPos) {
                target.add(source.get(i));
            }
        }
    }

进制转换

十进制与二进制、八进制、十六进制的转换

算法实现

  1. 其他进制转化为十进制(按权位展开
    如二进制数,其权重从右至左一次为1,2,4,…
    转换为十进制方法为:右边第一位*1+右边第二位*2+右边第三位*4+…
    "10101"转为方式为:11+02+14+08+1*16=21

  2. 十进制转换为其他进制(对进制数不断取余,余数为地位直至余数为零
    如十进制21,转换为8进制,21%8得5,八进制最低为5
    21/8取整得2,2%8得2,则次低位为2,
    2/8取整得0,终止,得到八进制数025

java代码实现

	/**
     * 二进制转十进制
     */
    private static void test2To10() {
        String num = "10101";

        String temp = num; //处理中的数字字符串
        int tempPos = num.length(); // 处理位数
        final int WEIGHT = 2;
        int posWeight = 1;
        int result = 0; //转换后的结果
        while (tempPos-- > 0) {
            result += Integer.parseInt(temp.substring(tempPos)) * posWeight;
            posWeight *= WEIGHT;
            temp = temp.substring(0, tempPos);
        }
        System.out.println(result);
    }
    /**
     * 十进制转二进制
     */
    private static void test10To2() {
        int num = 21;
        final int WEIGHT = 2;
        StringBuffer resultBuffer = new StringBuffer("");
        while(0 != num) {
            int i = num % WEIGHT;
            resultBuffer.insert(0,i);
            num = num / WEIGHT;
        }
        System.out.println(resultBuffer);
    }

java现有的实现

Interger对象提供有进制转换的方法:

  1. 十进制转换为其他进制: 16 toH 8 toO 2 toB
  2. 其他进制转换为十进制: parseInt(字符串, 进制); valueOf(字符串,进制); 定义其他进制整数:16 0x 8 0 20b,直接输出则为十进制
	/**
     * 进制转换算法:
     * toH toO toB
     * parseInt
     * 0x 0 0b
     */
    private static void jinZhiZhuanHuan() {
        System.out.println(Integer.toHexString(31));
        System.out.println(Integer.toOctalString(16));
        System.out.println(Integer.toBinaryString(16));
        System.out.println(Integer.parseInt("1f",16));
        System.out.println(Integer.parseInt("20",8));
        System.out.println(Integer.parseInt("10101",2));
        System.out.println(Integer.valueOf("10101",2));
        int i = 0b10101;  // 0x 0 0b
        System.out.println(i);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值