题目来自百度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; }