题目来自百度14年校招天津站笔试题,当时思路混乱导致被虐。
题目:n为正整数,求比这个数大且最小的不重复数,重复数为相邻两位数字相同,如1101为重复数,1231为不重复数。
举例:当n = 2222时,输出2301
方法:
1、暴力解决,最直观的方法
对于每一个大于n个数,都做一次判断,找出第一个满足条件的数。
2、O(m)算法,m为已知正整数的位数。
思路:
(1)先把数字变成字符串,此时字符串低位存储数字的低位。
(2)由高位到低位依次处理(字符串的高位代表着数字的高位),一旦高位某个位置pos正常改变,则从[0,pos - 1]之间的数据可以直接用0和1填充。这里的正常是指,pos位置改变后,对[pos+1,..]之间的数字没有影响,此时的特殊情况为包含"99"的情况。
(3)为了让数最小,可以现在pos - 1填充0,之后交错填充1,这里前提是pos的位置上是一个非0的数,如果是0,则pos - 1填充1,之后交错填充0。
(4)把字符串表示的数字变成数字。
时间复杂度:
假设数字长度为m,则数字变字符,遍历数字一遍,之后执行算法是最多遍历数字次数为3便,最后字符变数字遍历一遍,所以时间复杂度为O(m)。
举例:
待处理的数据: 98999
(1) 数字98999变成字符串"99989"
(2)这里假设nCurBit初始化指向8(99989),nLastBit初始化指向9(99989)。
<1> 由于有nCurBit不等于nLastBit,则nCurBit指向前一位,即为9,(99989),而nLastBit指向8(99989)。
<2> 此时仍然有nCurBit不等于nLastBit,仍然有nCurBit--,即nCurBit指向9(99989),nLastBit也指向9(99989)
<3> 此时nCurBit等于nLastBit,这是由于我们要求比98999大的数,即nCurBit要++。
<4> 这里比较特殊的一点是,nCurBit已经为9了(99989),再加会向前进位(会影响之前已经处理的位),此时加1后变成90099,其中此次变化影响了三个数,此时待处理的位置应该回退到被影响的位的第一位中(90099),这是因为进位后的某些位可能和原来的某些数字是重复的。
<5> 此时nCurBit指向第一个被影响的位置(指向9,即90099),nLastBit也指向9(90099),而继续往左处理
<6> 之后,还是采用之前的策略处理,直到某个数加1后,不会对那些已经处理好的数字产生影响,就停止。之后剩余的数字直接填充0或1即可。
貌似说的混乱,凑合瞅瞅。。
代码:
(1)暴力解决
#include <iostream>
#include <assert.h>
using namespace std;
bool IsNoRepetition(int nNum)
{
int nCurBit = 0;
int nLastBit = -1;
while (nNum)
{
if (-1 == nLastBit)
{
nLastBit = nNum % 10;
}
else
{
nCurBit = nNum % 10;
if (nCurBit == nLastBit)
{
return false;
}
nLastBit = nCurBit;
}
nNum /= 10;
}
return true;
}
int MaxNum_Force(int nNum)
{
assert(nNum > 9);
while (!IsNoRepetition(nNum))
{
nNum++;
}
return nNum;
}
int main()
{
int nNum = 0;
cin>>nNum;
cout<<MaxNum_Force(nNum)<<endl;
system("pause");
return 1;
}
(2)O(n)算法
#include <iostream>
#include <assert.h>
using namespace std;
char* IntToString(int nNum)
{
assert(nNum > 9);
int nCur = 0;
char* pStrNum = new char[20];
memset(pStrNum,0,sizeof(char) * 20);
while(nNum)
{
pStrNum[nCur++] = nNum % 10 + '0';
nNum /= 10;
}
return pStrNum;
}
int StringToInt(char* pStrNum)
{
assert(pStrNum != NULL);
int nNewNum = 0;
int nLen = strlen(pStrNum);
while (nLen >= 1)
{
nNewNum *= 10;
nNewNum += (pStrNum[nLen - 1] - '0');
nLen--;
}
return nNewNum;
}
int MaxNum(int nNum)
{
assert(nNum > 9);
char* pStrNum = IntToString(nNum);
int nCur = strlen(pStrNum);
char cLastBit = pStrNum[--nCur];
nCur--;
while(nCur >= 0)
{
if (pStrNum[nCur] != cLastBit)
{
cLastBit = pStrNum[nCur--];
}
else if(pStrNum[nCur] != '9') //nCur位不等于9,则直接加1
{
pStrNum[nCur]++;
break;
}
else //nCur位等于9,则会影响前面已经处理的数,需要回退
{
while(pStrNum[nCur] == '9')
{
pStrNum[nCur++] = '0';
}
//进位
if (pStrNum[nCur] == 0)
{
pStrNum[nCur] = '1';
}
else
{
pStrNum[nCur]++;
}
cLastBit = pStrNum[nCur + 1];
if (cLastBit != pStrNum[nCur])
{
break;
}
}
}
nCur--;
//剩余的位直接填充0或者1
while (nCur >= 0)
{
if (pStrNum[nCur + 1] == '0')
{
pStrNum[nCur] = '1';
}
else
{
pStrNum[nCur] = '0';
}
nCur--;
}
int nNewNum = StringToInt(pStrNum);
delete[] pStrNum;
return nNewNum;
}
int main()
{
int nNum = 0;
cin>>nNum;
cout<<MaxNum(nNum)<<endl;
system("pause");
return 1;
}