第2章 数字之魅——找符合条件的整数

找符合条件的整数

问题描述

  任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0。

  解决这个问题首先考虑对于任意的N,是否这样的M一定存在。可以证明,M是一定存在的,而且不唯一。
简单证明:因为

这是一个无穷数列,但是数列中的每一项取值范围都在[0, N-1]之间。所以这个无穷数列中间必定存在循环节。即假设有s,t均是正整数,且s<t,有 。于是循环节长度为t-s。于是10^s = 10^t。因此有:
,所以

例如,取N=3,因为10的任何非负次方模3都为1,所以循环节周期为1.有:

分析与解法

【解法一】

  给定N,令M从2开始,枚举M的值直到遇到一个M使得N*M的十进制表示中只有1和0。

代码如下:

 1 package chapter2shuzizhimei.findminint;
 2 /**
 3  * 找符合条件的整数
 4  * 【解法一】
 5  * @author DELL
 6  *
 7  */
 8 public class FindMinInt1 {
 9     //判断整数的十进制表示中是否只有0和1
10     public static boolean hasOnlyOneAndZero(long x){
11         while(x!=0){
12             if(x%10>=2)
13                 return false;
14             x /= 10;
15         }
16         return true;
17     }
18     //找符合条件的最小的正整数
19     public static long findMin(long n){
20         for(int i=2;;i++){
21             if(hasOnlyOneAndZero(i*n))
22                 return i;
23         }
24     }
25
26     public static void main(String[] args) {
27         long n = 3;
28         System.out.println("使得与"+n+"的乘积的十进制表示形式里只有1和0的最小正整数为:"+findMin(n));
29
30     }
31
32 }

程序运行结果如下:

使得与3的乘积的十进制表示形式里只有1和0的最小正整数为:37

【解法二】

  求出10的次方序列模N的余数序列并找出循环节。然后搜索这个余数序列,搜索的目的就是要在这个余数序列中找到一些数出来让它们的和是N的倍数。例如N=13,这个序列就是1,10,9,12,3,4然后不断循环。很明显有1+12=13,而1是10的0次方,12是10的3次方,所以这个数就是1000+1=1001,M就是1001/13=77。

【解法三】

  因为N*M的取值就是1,10,11,100,101,110,111,......所以直接在这个空间搜索,这是对方法一的改进。搜索这个序列直到找到一个能被N整除的数,它就是N*M,然后可计算出M。例如N=3时,搜索树如下:

上图中括号内表示模3的余数。括号外表示被搜索的数。左子树表示0,右子树表示1.上图中搜索到第二层(根是第0层)时遇到111,它模3余数为0.所以N*M=111, M=111/3=37。

具体实现代码如下:

 1 package chapter2shuzizhimei.findminint;
 2
 3 import java.util.LinkedList;
 4 import java.util.Queue;
 5
 6 /**
 7  * 找符合条件的整数
 8  * 【解法三】
 9  * @author DELL
10  *
11  */
12 public class FindMinInt3 {
13
14     //找符合条件的最小的正整数
15     public static long findMin(long n){
16         Queue<Long> queue = new LinkedList<Long>();
17         queue.add((long) 1);
18         long temp;  //存放取出的队首元素
19         while(true){
20             temp = queue.poll();
21             if(temp%n==0)
22                 return temp/n;
23             queue.add(temp*10);
24             queue.add(temp*10+1);
25         }
26     }
27
28     public static void main(String[] args) {
29         long n = 3;
30         System.out.println("使得与"+n+"的乘积的十进制表示形式里只有1和0的最小正整数为:"+findMin(n));
31
32     }
33
34 }

程序运行结果如下:

使得与3的乘积的十进制表示形式里只有1和0的最小正整数为:37

【解法四】

  对方法三的改进。将方法三的搜索空间按模N余数分类,使得搜索时间和空间都由原来的指数级降到了O(N)。改进的原理:假设当前正在搜索由0,1组成的K位十进制数,这样的K位十进制数共有2^k个。假设其中有两个数X、Y,它们模N同余,那么在搜索由0、1组成的K+1位十进制数时,X和Y会被扩展出四个数:10X, 10X+1, 10Y, 10Y+1。因为X和Y同余(同余完全可以看作相等),所以10X与10Y同余,10X+1与10Y+1同余。也就是说由Y扩展出来的子树和由X扩展产生出来的子树产生完全相同的余数,如果X比Y小,那么Y肯定不是满足要求的最小的数,所以Y这棵子树可以被剪掉。这样,2k个数按照模N余数分类,每类中只保留最小的那个数以供扩展。原来在这一层需要搜索2k个数,现在只需要搜索O(N)个数。例如,当N=9时,第0层是1(1),

  如上图所示,第2层的110,第三层的1010、1110都因为同一层有和它同余且更小的数而被剪掉。如果按照方法三搜索,第三层本来应该有8个结点,但现在只有4个结点。

只需要将10k%N的结果与余数信息数组里非空的元素相加,再去模N,看看会不会出现新的余数。

具体代码如下:

 1 package chapter2shuzizhimei.findminint;
 2
 3 import java.util.LinkedList;
 4 import java.util.Queue;
 5
 6 /**
 7  * 找符合条件的整数
 8  * 【解法四】
 9  * @author DELL
10  *
11  */
12 public class FindMinInt4 {
13
14     //找符合条件的最小的正整数
15     public static long findMin(long n){
16         long[] a = new long[(int) n]; //a[i]记录模n余i之后的数值
17         for(int i=0;i<n;i++){ //初始化数组
18             a[i]=-1;
19         }
20         int factor = 1;
21         a[1] = 1;
22         int i;
23         for(i=0; ;i++){
24             factor *= 10;
25             int current = (int) (factor % n);
26             if(current == 0){
27                 a[current] = factor; //保存余数为0的数
28                 return factor/n;
29             }
30             if(a[current]==-1){
31                 a[current] = factor;
32             }
33             //将当前的余数跟余数数组里面的余数相加mod n
34             int k; //存放前面的余数
35             //将当前的余数与前面的余数都相加再模上n,若产生新的余数的数值保存下来,另外若得到与以前相同的数值,不更新,因为要保存最小的
36             for(k=1;k<n;k++){
37                 if(a[k]==-1)
38                     continue;
39                 int newyu = (int) ((current+k)%n);
40                  //新产生的余数不存在,将factor与k相加,得到新的数,只与小于factor的数进行想加,不要与后面的相加,与factor相加的数一定要小于factor
41                 if(a[newyu]==-1&&a[k]<factor){
42                     a[newyu] = factor + a[k];
43                     if(newyu==0)
44                         return a[newyu]/n;
45                 }
46             }
47         }
48     }
49
50     public static void main(String[] args) {
51         long n = 3;
52         System.out.println("使得与"+n+"的乘积的十进制表示形式里只有1和0的最小正整数为:"+findMin(n));
53
54     }
55
56 }

程序运行结果如下:

使得与3的乘积的十进制表示形式里只有1和0的最小正整数为:37

参考链接:

编程之美——找符合条件的整数

编程之美 找符合条件的整数

编程之美 找出符合条件的整数

时间: 2024-10-21 16:32:00

第2章 数字之魅——找符合条件的整数的相关文章

【编程之美】2.8 找符合条件的整数

给定一个正整数N,求一个最小的正整数M(M > 1),使得N * M的十进制表示中只有0和1. 我的思路: 从最低位到最高位找M,每次使得乘积的最后面多一位符合0.1的条件. 那么先找能够让末尾数字变成0的备选项 举例若N的个位数是9  考虑从后面来的进位 c 让 x * 9 + c 的末尾是0或1 设个位数字为9 则eligibleNum中存储的数字eligibleNum[0][0] = 0 因为9 * 0 + 0 = 0 末尾符合0或1 eligibleNum[0][0] = 9 因为9 *

(转)找符合条件的整数

题目:任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0.解决这个问题首先考虑对于任意的N,是否这样的M一定存在.可以证明,M是一定存在的,而且不唯一.简单证明:因为 这是一个无穷数列,但是数列中的每一项取值范围都在[0, N-1]之间.所以这个无穷数列中间必定存在循环节.即假设有s,t均是正整数,且s<t,有 .于是循环节长度为t-s.于是10^s = 10^t.因此有:,所以 例如,取N=3,因为10的任何非负次方模3都为1,所以循环节周期为1.

【编程之美】找符合条件的整数

任意给定一个正整数N,求一个最小的正整数M(M > 1),使得N*M的十进制表示形式里只含有1和0. 看了题目要求之后,我们首先想到从小到大枚举M的取值,然后再计算N*M,最后判断它们的乘积是否只含有1和0.大体思路可以用下面的伪代码实现: 1 for (M = 2; ; M++) 2 { 3 product = N * M; 4 if (hasOnlyOneAndZero(product)) 5 output N, M, product, and return; 6 } 但问题很快就出现了,什

编程之美---找符合条件的整数

题目:任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0. 解法:原问题转化为求一个最小的正整数X,使得X的十进制表示形式里只含有1和0,并且X被N整除.于是乎就成了遍历二进制整数一样遍历X的各个取值,但是如果X的最终结果又K位,则要循环搜索2K 次.因此,可以建立一个长度为N的“余数信息数组”,这个数组的第i位保留已经出现的最小的模N为i的X.用BigInt[i]可能很大,只须记下1的位置即可. 1 for(i=0;i<N;i++) 2 BigIn

找符合条件的整数

题目: 任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式只含有1和0 . 分析: 将问题"求一个最小的正整数M,使得N*M的十进制表示形式里只含有1和0"转换为求一个最小的正整数X,使得X的十进制表示形式里只含有1和0,并且X被N整除.

编程之美2.8 | 找符合条件的整数

思路还是相当地巧妙. 求余数的话,(a+b)%n=(a%n+b%n)%n; 用vector来表示整数的话(出现1的位置),可以避免溢出. 注意第20行,在更新remainders[(j+r)%n]时,要确保每个remainders的每个序列都是递增的,不能存在相等的情况. 1 #include <time.h> 2 #include <math.h> 3 #include <stdlib.h> 4 5 using namespace std; 6 7 long long

编程之美2.8——找符合条件的整数

任意给定一个正整数N,求一个最小的正整数M(M>1),使得N*M的十进制表示形式里只含有1和0. 如N=3,M=39,N*M=111. [思路] 这么难的思路打死我也想不到[email protected][email protected]|||||.. 将题目转换为,求一个数X,使得X%N=0且X的十进制表示只含有1和0. 维护一个“余数数组”,对于从0到N-1的每一个余数,都有相应的最小X: 高位可以利用低位的余数归队,X=10^k+Y(10的k次方,^表示次方)X%N=(10^k%N+Y%

编程之美 找出符合条件的整数

好不容易把内容看懂~ 最主要的一句话:只需要将10k%N的结果与余数信息数组里非空的元素相加,再去模N,看看会不会出现新的余数~ 时间太紧迫~先把自己写的代码贴上,以后再详解 1 int FindMin(int N) 2 { 3 if(N <= 1) 4 return N; 5 6 int* A = new int[N];//这个是记录模N余i之后的数值 7 8 memset(A, -1, sizeof(int) * N); 9 int factor = 1; 10 A[1] = 1; 11 1

编程之美——符合条件的整数

问题:给定整数N,求最小整数M,使得N*M的十进制表示中只含有1和0: 当M很大时,机器可能不能表示M,对问题转化:求以最小整数X,使得X的十进制表示中只含1和0,并且被N整除: 此问题必定有解:可参考:http://blog.csdn.net/spaceyqy/article/details/38337387 代码实现(具体思路参考编程之美或:http://www.cnblogs.com/jfcspring/p/3776388.html): 1 #include<iostream> 2 #i