百度14年校招笔试题:
n 为正整数,求比这个数大且最小的不重复数,重复数为相邻两位数字不相同
如: n = 2222时,输出2301
解题思路:(受insistGoGo 启发,博文地址http://blog.csdn.net/insistgogo/article/details/12240495, 在此表示感谢)
考察 9898996
若找比此数大且最小的不重复数,直接找到此数序列中(从高位开始)首个重复的数字(这里是99),并且将重复数字的低位自增1,如果有进位则进位
这样操作出来会得到一个新数(这里是9899006),得到的新数可能会有新的重复数字出现,对其做同样操作,直到不产生新的重复数字为止
然后将最后一次自增位之后的数字序列变成0101序列,则得到的数字即为要找的数字
文字叙述可能难以理解,下面让我们考察几个数,来理解查找的过程
1. n (输入的数)本身有重复的数
如 9898996
9898996 ---> 9899006 (查找到首个重复数字99,然后对99的低位9自增1) --> 9900006 (因为产生新的重复数字,所以做同上操作) --> 10000006
--> 10100006 (首个重复数字00,自增1) --> 10101010 (没有产生新的重复数字,将01之后的数字序列变成0101序列)
则10101010 就是 大于 9898996 且是最小的不重复数
如 85499
85499 --> 85500 --> 85600 --> 85601
如 8325996
8325996 --》 8326006 --》 8326010
以上都是对99重复的例子,很容易发现,如果数字序列中出现99,则对99做自增后,会影响到99之前的两位
其他重复例子:如56332
56332 --》 56340
如 56443 --》 56450
很容易发现 00 - 88 的重复属于同一类型的, 只需对重复数字的低位自增,然后将后续序列换成0101序列
2. n (输入的数)本身无重复的数
本身无重复的数,是不是直接自增1就可了(既最后一位自增1)? 情况并没有这么简单
如 36954 自增1 变成 36955 (自增1,产生新的重复数字)
如 36549 自增1 变成 36550 (自增1,产生新的重复数字)
如 36539 自增1 变成 36540 (这个尾数也是9呢,但自增1之后,就是要找的数啦)
还有如呢,我还没菊丸栗子呢
如 36956 这种最喜欢啦 因为自增1 查找就结束了 36957 就是要找的
好了,栗子举玩了(谁给我买我最喜欢的板栗啊,都被我举完了哇 呜呜呜~~~)。
透过栗子,我想应该也能发现些什么了吧(发现啥? 规律规律规律啊)
总结一下:
1. n 本身包含重复,重复的类型有两种:
1-1 : 99 :自增1 之后,会影响到前两位数字,所以在自增之后,指针(用两指针指向当前的两位被考察数字,如99)需向前移动两位,确认是否产生新的重复数字
1-2 : 00 - 88:喜欢这个重复,因为自增1之后,不会影响到前位数字(既指针不需前移),替换后续序列为0101,就可以退出了
2. n本身不包含重复,类型有三种:
2-1 : (x+1)x9,末尾为9,自增1之后,会影响到前一位数字,指针需向前移动1位(两个指针都前移),查看是否产生新的重复数字,若产生,则变为 1中重复情况
2-2 : (x+1)x,尾数为x,而前一位比其大1,自增1,会产生新的重复数字,指针不需向前移动,变为1中重复情况
2-3 : x9 和 yx,x9中的x的前一位数不比x大1,yx不满足2-1 和 2-2中要求,且x不为9, 可直接自增1,然后找到所要找的数,退出。
好了,理解以上的内容,就可以编码实现。
此算法复杂度为O(m),m为n的位数。
用两个指针fpStrNum 和 spStrNum分别指向数的最高位和次高位。
#include <iostream>
#include <cstdlib>
#define MAX 100
using namespace std;
char* getStrNum(int nNum)
{
char *pStrNum = new char[MAX];
memset(pStrNum, 0, sizeof(char)*MAX);
int i=0;
while(nNum)
{
pStrNum[i++] = nNum % 10 + '0';
nNum = nNum / 10;
}
return pStrNum;
}
void increase(char *p)
{
if(0==*p) *p = 1+'0';
else {
if(*p<'9') *p += 1;
else {
*p = '0';
increase(p+1);
}
}
}
void set01(char *start, char* end)
{
int flag = 0;
while(start >= end)
{
if(flag == 0)
{
*start = '0';
flag = 1;
}
else {
*start = '0' + 1;
flag = 0;
}
start--;
}
}
char* MinLargeNumber(int nNum)
{
char* pStrNum = getStrNum(nNum);
int length = strlen(pStrNum);
if(1 == length)
{
increase(pStrNum);
return pStrNum;
}
char* fpStrNum = pStrNum + length -1;
char* spStrNum = pStrNum + length -2;
while(fpStrNum > pStrNum)
{
if(spStrNum > pStrNum && *fpStrNum != *spStrNum)
{
fpStrNum--;
spStrNum--;
continue;
}
// 含重复
if(*fpStrNum == *spStrNum)
{
// 00 - 88
if(*spStrNum < '9') {
increase(spStrNum);
set01(spStrNum-1, pStrNum);
break;
}
// 99
else {
increase(spStrNum);
fpStrNum += 2;
spStrNum += 2;
continue;
}
}
// 不含重复
else {
// (x+1)x9
if(*spStrNum == '9' && (*(fpStrNum+1) - *fpStrNum) == 1)
{
increase(spStrNum);
fpStrNum += 1;
spStrNum += 1;
continue;
}
// (x+1)x
else if((*fpStrNum - *spStrNum) == 1)
{
increase(spStrNum);
continue;
}
// x9 or yx
else {
increase(spStrNum);
set01(spStrNum-1, pStrNum);
break;
}
}
}
return pStrNum;
}
int main(int argc, char *argv)
{
int n;
while(scanf("%d", &n) != EOF)
{
char *pStrNum = MinLargeNumber(n);
int len = strlen(pStrNum);
char *end = pStrNum+len-1;
while(end>=pStrNum) printf("%c", *end--);
printf("\n");
}
system("pause");
return 0;
}
好啦,收工回家晾衣服