百度2014届校园招聘软件研发岗位深圳站的笔试中有这样一题:输入一个任意正整数,输出一个比输入值要大但又不重复的最小数(不重复是指:相邻两个数字不相同,例如1101是重复,1234不重复,1201不重复),比如输入1234,应当输出1235,而不是 1232、1236、4321等。
分析思路:
一,考虑数值区间。尽量选择一个容器比较大的类型,以便不溢出,unsigned long long就比较适合。当然,也可以考虑数组/字符串形式表示任意大的数值,只是,题目只是讲“输入一个任意正整数”,所以我们在接口上也就暂不考虑这种形式。
二,数值表达形式。虽然接口上没有采用以数组/字符串形式表示数值,但我们应当在程序内部考虑这一形式,方便“不重复”检查。
三,先保大再不重。从数值的最高位起,两两检查是否相同,如果相同,则在低位加一,并检查级联进位情况,记录最后有加一操作的位置。 从这一位置开始【不包含它本身】向低位方向,顺次按010101...规律填充,如此保证取值最小。
代码示例:
/*
将数值数组中指定位置值加一,并返回向前推进到的位置
由调用者保证数组中的最高位的前一位为0值
*/
int addOne2NumArray(char num[], int p)
{
while (true)
{
if (num[p] < 9)
{
++num[p];
break;
}
else
{
num[p]=0;
++p;
}
}
return p;
}
/*
算法入口, 获得“最小但不重复数”
*/
uint64 getMyNum(const uint64 N)
{
const int maxNumLength = 64;
char num[maxNumLength];
//将数分解到数组中
int H =0; //记录数值的最高位
uint64 tmpN =N;
while (tmpN)
{
num[H] = tmpN % 10;
tmpN /= 10;
++H;
}
num[H] =0; //此处重要,预设数值结束位,方便后续操作
//从高至低 检查数字是否有重复
int L =H -2; //记录数值中相同的位置
for (; L >= 0; --L)
{
if (num[L] == num[L+1])
{
break;
}
}
//在重复数位处的低位加一
L=addOne2NumArray(num, (L<0)?0:L);
//检查有进位的,是否又和前面的重复
while (true)
{
if (num[L] == num[L+1])
{
L =addOne2NumArray(num, L);
}
else
{
break;
}
}
//从有进位的起,后面的数据尽量取小
for (int i = L -1; i >= 0; --i)
{
num[i] = !num[i +1] ; // num[i +1]==0 也可以
}
//组装数据输出
for (int i = H; i >= 0; --i)
{
tmpN = tmpN *10 + num[i];
}
return tmpN;
}
测试结果: