2.8 寻找符合条件的数

来源:互联网 发布:淘宝seo是干什么的 编辑:程序博客网 时间:2024/05/21 15:55

1. 前言

本文的一些图片, 资料 截取自编程之美

2. 问题描述

这里写图片描述

3. 问题分析

这个问题主要 给定一个n, 然后寻找最小的能够整除n, 的并且只含有0, 1 的十进制数
解法一 : 穷举 0, 1, 10, 11, 100, 101, 110, 111, …
解法二 : 缓存<余数, 除以n余数为键的最小的整数>, 使用一个num计数, num从1开始, 每次迭代num*10, 遍历缓存表[遍历所有缓存余数], 如果num + entry.key能够被n整除, 那么则说明num + entry.key即为所求, 否则 判断num + entry.key 对应的余数不存在于缓存表, 则将<余数, num + entry.key> 添加到缓存表中, 所以缓存表中保存的就是 余数和余数对应的最小的能够被n整除的数字

这个思路减少了一些余数相同的数, 的重复计算 [比如 n为3, num为100, 假设之后的数为1, 10 [拼凑出101, 110], 因为1, 10 除以3 都余1 并且100除以3余数固定 , 所以这两个计算实际上是重复的, 而这里的思路, 就减少了这种重复的计算 ]

但是第二种思路的优势, 确实是挺难的, 吧备选的数字(们), 限制在了最多为n个
比如n为13, 而现在num跑到了1000000, 这样1000000, 之后的备选数字有2^6 64个, 而第二种思路, 将备选数字限制到了最多12个

编程之美分析原图 :
这里写图片描述

4. 代码

/** * file name : Test14ModNGotOnly01.java * created at : 9:21:48 AM May 23, 2015 * created by 970655147 */package com.hx.test03;import com.hx.util.Log;public class Test15ModNGotOnly01 {    // 获取能够整除n 并且只包含01的整数    public static void main(String []args) {        long start = System.currentTimeMillis();        Random ran = new Random();        int n = ran.nextInt(500);//      int n = 111;        Log.log(n);        findModGotOnly0101(n);        Log.enter();        findModGotOnly0102(n);        Log.horizon();        long spent = System.currentTimeMillis() - start;        Log.log("spent : " + spent + " ms...");    }    // 穷举 1, 10, 11, 100, ...    public static void findModGotOnly0101(int n) {        int i = 1;        boolean isFound = false;        while(!isFound) {            int num = Integer.valueOf(Integer.toBinaryString(i ++ ));            if((num % n) == 0 ) {                isFound = true;                Log.log(num);                break;            }            if(num > (Integer.MAX_VALUE >> 1) ) {                Log.log("specified number not find...");                break;            }        }    }    // num : 1 -> 10 -> 100 -> ...    // 先检查modValues中的对象    // 在检查num能否被n整除    // modValues存放于n计算<取得的模[除了0], 最小的值>        // 比如 n为3   则1 -> 1, 2 -> 11    // tmp用于存放本次计算中可以加入modValues中的entry[因为 如果直接在循环中加入modValues的话  会打乱计算]        // 比如  如果num为100  如果计算得到了一个(1111 -> 3)可以加入modValues         // 如果直接加入的话  下一次循环计算的时候 会将这个1111也一并计算了 导致计算的不准确[1000 + 1111 = 2111]]        // 所以先将可存储的entry 存入tmp中  循环结束  加入到modValues中    public static void findModGotOnly0102(int n) {        Map<Integer, Integer> modValues = new HashMap<Integer, Integer>(n - 1);        Map<Integer, Integer> tmp = new HashMap<Integer, Integer>( (n >> 1) );        int i = 1;        int num = i;        boolean isFound = false;        while(!isFound) {            int modVal = num % n;            tmp.clear();            for(Map.Entry<Integer, Integer> entry : modValues.entrySet() ) {                int mayBeRes = entry.getKey() + modVal;                int modVal02 = mayBeRes % n;                if(modVal02 == 0) {                    isFound = true;                    Log.log(num + entry.getValue() );                    break;                } else {                    if(!modValues.containsKey(modVal02) ) {                        tmp.put(modVal02, num + entry.getValue());                    }                }            }            modValues.putAll(tmp);            if(modVal == 0) {                isFound = true;                Log.log(num);            } else {                if(!modValues.containsKey(modVal) ) {                    modValues.put(modVal, num);                }            }            // 如果快要越界了还没有找到 则视为找不到了            if(!isFound && (num > (Integer.MAX_VALUE >> 1)) ) {                Log.log("specified number not find...");                break;            }            num *= 10;        }    }}

5. 运行结果

这里写图片描述

6. 总结

穷举的想法当然不是很难想到
第二种思路是非常巧妙的, 再再一次证明了数学与算法的紧密联系

注 : 因为作者的水平有限,必然可能出现一些bug, 所以请大家指出!

0 0