求比指定数大且最小的“不重复数”
题目:
给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数”的含义是相邻两位不相同,例如1101是重复数,而1201是不重复数。(百度2014校招笔试题目)
解法一:(普通,低效)
思路:
这道题目我也没有什么特别出彩的算法,就是按照常规思路来求解,首先要理解什么叫做“不重复数”,这是解题的关键之一,相邻两位不相同的数即为“不重复数”;还有一个地方要注意的就是“求比这个数大且最小的”,就是在比给定数大的不重复数中找到最小的!理解了这两个地方,这道题目就可以着手求解了!
我用一个实例来说说我的思路,加入给定的正整数为11233:
用最常规的方法,就是每次对这个数加1,判断是不是“不重复数”,加1后为11234,有两个1重复了,于是继续加1,……,那么主要就在判断是不是“不重复数”上面了,我设置了两个变量,是currentBit, lastBit,顾名思义,lastBit保存上一个数位的值,currentBit保存当前数位的值,拿整数12345来说,就是初始化lastBit = 5,然后计算currentBit = 4;下一步,把currentBit 值赋给lastBit,即lastBit = 4,计算currentBit = 3;依次类推。
说到这里,很多朋友觉得可以有更加高效的方法,小难点有4:
1、因为可以直接定位到“重复”的数位那里,比如12344,我们可以直接定位到个位数4和十位数4上面,然后在低位数(这里就是个位数)上加1即可,事实上,不是如此简单,假设是对整数12199呢?还能简单的加1操作吗,加1之后结果为12200,那结果显然是错的,当然这也是可以处理的,处理方法就是把12200继续拿到循环去判断是不是“非重复数”;
2、这里又产生一个问题,因为“重复“的数位可能不止一对,有可能有多对,比如整数11233,定位“33”之后变为“34”,定位“11”之后变为“12”,结果就是12234。又有重复的地方,就是“22”。继续拿到循环去重复;
3、还有要注意的是,你的程序设计,是如何存储数位的值的,是一个一个数位的值求出来呢?还是像我这样设置一个前后索引?每个数位取值,程序会变得繁琐复杂,不易读懂,如果是设置前后索引,则要注意程序退出循环的条件!
4、对于存在多对“重复”数位的正整数,数位“重复”的定位和变换,是从高位到低位,还是从低位到高位呢?正确的应该是从高位到低位,这与我们的程序设计也带来了不便。
/*给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数的含义是相邻两位不相同,例如1101是不重复数”*/#include <stdio.h>#include <stdlib.h>int getNumNonrepetition(const int NumGived){int flag = 0;//为0表示该数不是“不重复数”int numRepeat = NumGived;int numTemp = 0;//int currentBit = 0, lastBit = 0;//前后数位索引while(1){numRepeat++;//初始化后索引numTemp = numRepeat;lastBit = numTemp % 10;numTemp /= 10;flag = 1;//判断该数是不是“非重复数”while(numTemp != 0){currentBit = numTemp % 10;numTemp /= 10;if(lastBit == currentBit){flag = 0;break;}lastBit = currentBit;}if(flag == 1)//该数为不重复数,返回{return numRepeat;}}}int main(void){int NumGived = 19922884;int result = getNumNonrepetition(NumGived);printf("the number is %d\n", result);return 0;}
结果:
解法二:(高效)
思路:
1、把整数放到字符数组里面去,从高位为低位(用变量i)扫描,找到重复的数位,重复数位为“99”跳到第2步,否则跳到第3步,若没有重复的数位,则该数为不重复数,返回;
2、遇到“99”的重复数,则把“99”改为“00”,然后在“99”前面一位字符加1,把扫描的地方定位在“99”往高位方向的第2位,比如是1299,变换后为1300,然后把扫描变量 i 定位在1这一数位上,返回第1步;
3、遇到非“99”的重复数,则直接在低位加1,后面依次变为010101……,结果就是最小的不重复数,返回改值;
代码:
#include <iostream>#include <cstdlib>#define MAX_NUM 100using namespace std;void getNonrepeatNumber(const long long val);int main(void){long long val = 121;getNonrepeatNumber(val);return 0;}void getNonrepeatNumber(const long long val){char buf[MAX_NUM];memset(buf, '0', sizeof(char)*MAX_NUM);sprintf(buf+1, "%lld", val);//第一个位置空掉,用来保存进位int len = strlen(buf);cout<<"原数为:"<<buf+1<<endl;int i = 1;bool first = true;while(true){while(i + 1 < len && buf[i] != buf[i+1])i++;//如果是第一次扫描发现原数本身就是一个不重复数,则在其最低位+1//+1时进行判断,如果个位为9,则变为0,再进位,否则直接+1//+1后判断会不会跟前一位重复if( (i == len - 1) && first){if(buf[i] == '9'){buf[i] = '0';i--;}buf[i] += 1;i--;first = false;continue;}//如果是第二次扫描到此,则直接退出,表示当前数为最小不重复数else if(i == len - 1)break;//重复的数位为99这种情况,将这两位全部置0,高位加1if(buf[i+1] == '9'){buf[i+1] = '0';i--;buf[i+1] = '0';i--;buf[i+1] += 1;}else{buf[i+1] += 1;i += 2;bool flag = true;//后续全部设为0101……,这个时候肯定是不重复数了,所以可以跳出循环while(i < len)if(flag){buf[i++] = '0';flag = false;}else{buf[i++] = '1';flag = true;}break;}}cout<<"最小不重复数为:";//如果是99开头的数字,高位可能会进位,判断是否为零,不为零则有进位,需打印出来if(buf[0] == '0')cout<<buf+1<<endl;else cout<<buf<<endl;}
结果:







浙公网安备 33010602011771号