找符合条件的整数

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

     第一想法:从小到大枚举M的取值,然后再计算N*M,最后判断它们的乘积是否只含有1和0。该方法时间复杂度太高。

     第二想法:因为问题要求N*M的十进制表示形式里只含有1和0,尝试去搜索N*M,需要搜索的空间要小很多。

     终极思路:(避免多于的除法验证余数)如1%3=1;10%3=1;101%3=2那么我们可以知道110%3=2。即1和10加上相同的数,他们的余数都相同,所以我们只需要考虑1,11,101,1001而不用考虑10,110,1010。对于modN同余的数,只需要记录最小的一个。形式化论述:假设已经遍历了X的十进制表示有K位时的所有情况,而且也搜索了X=10^K的情况,设10K%N=a。现在要搜索X有K+1位的情况,即X=10K+Y,(0<Y<10K)。把Y按照其对N的余数分类,我们搜索的空间将被分成N-1个子空间。对于每个子空间,其实只需要判断其中最小的元素加上10K是否被N整除即可,而没有必要判断这个子空间里所有元素加上10K是否能被N整除。

     伪代码描述:BigInt[i]表示模N等于i的十进制表示形式里只含1和0的最小整数。由于BigInt[i]可能很大,又因为它只有0和1,所以只需要记下1的位置即可。如1001记为(0,3)=10^0+10^3。即BigInt的每个元素是一个变长数组,对于模N等于i的最小X,BigInt的每个元素将存储最小X在十进制中表示1的位置。我们的目标就是求BigInt[0]。

public static String find01Int(int N){

                   intNoUpdate = 0;

                   LinkedList<Integer>[]kt = new LinkedList[N];

                   for(int i = 0;i<N;i++){

                            kt[i] = new LinkedList<Integer>();

                   }

                   kt[1].push(0);

                   //i=1从十位开始,显然,个位1已经放入kt[1]

                   for(int i = 1,j=10%N;;i++,j=(j*10)%N){

                            boolean flag = false;

                            if(kt[j].size()==0){

                                     kt[j].clear();

                                     kt[j].push(i);

                            }

                            for(int k = 1;k<N;k++){

                                     //用于判断含有余数的项并且是低位(<i),并加上高位后产生的余数是新的

                                     //余数,则把得出该余数的最小值记录下来

                                     if((kt[k].size()>0)&&

                                                        (i>kt[k].peek())&&

                                                        (kt[(k+j)%N].size()==0)){

                                               flag= true;

                                               //这步赋值很重要,不能漏,因为该最小值前面几项在kt[k]

                                               for(int p = 0;p<kt[k].size();p++){

                                                        kt[(k+j)%N].add(kt[k].get(p));

                                               }

                                               kt[(k+j)%N].push(i);

                                     }

                            }

                            if(flag==false)

                                     NoUpdate++;

                            else

                                     NoUpdate =0;

//如果经过一个循环都没能对BigInt进行更新,就是无解,跳出,或者BigInt[0]已经找到也跳出

                            if(NoUpdate == N||kt[0].size()>0)

                                     break;

                   }

                  if(kt[0].size() == 0){

                            return null;

                   }

                   else{

                            StringBuilder sb = new StringBuilder();

                            //输出也很有技巧,例如4的话,kt[0]记录的是2,此时,要输出100,所以要注意//收尾操作

                            sb.append(1);

                            for(int i = kt[0].pop();;){

                                     int temp = 0;

                                     boolean t = true;

                                     if(kt[0].size()!=0){

                                               temp= kt[0].pop();

                                               t= false;

                                     }

                                     for(int k = i-1;k>temp;k--){

                                               sb.append(0);

                                     }

                                     if(!t)

                                               sb.append(1);

                                     else

                                               sb.append(0);

                                     i = temp;

                                     if(kt[0].size()==0)break;

                            }

                            return sb.toString();

                   }

         }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值