好像好久都没在编程栏目下投新稿了(
那就来篇水点的,顺便测试下代码高亮插件
报了华为编程大赛,找了去年的题,看到了这道:
如果一个数字十进制表达时,不存在连续两位相同,则称之为“不重复数”。 例如,105、1234和12121都是“不重复数”,而11、100和1225不是。 给定一个正整数A,返回大于A的最小“不重复数”。A小于100000
初见一看,从所给之数开始依次加一,判断新的数是否是重复数就行了,可谓是最笨而又保险的做法
很快写完后,恰好有友人过来一同讨论,是否有更优的算法呢?
先从这个每步+1着手,诸如122421这样的数,千位和万位重复,再从个位加真是太累了;于是改成从高位向低位遍历,遇到重复的邻近位就把低位+1,至少效率会比+1好多了;
对122421采用这种做法,会+1000变成123421,看上去的确是不重复了,但却丢失了最小性(最小的应该是123010)
因此,在修改重复位之后,还需要把低位重置,重置成0、1相邻的序列,就能弥补最小性了
例如122121,先+1000变为123121,再从123后面填入序列,得到123010;
例如120014,先+100变为120114,再从1201后面填入序列,得到120101
在这种做法下,循环数量可谓是大大减少了,很多情况下更是一步到位;但是依然没有摆脱“自增修改->判断是否为重复数”的循环试探法
要得到一步到位的稳定法,还需考虑进位的情况:
例如1219922,在遍历到9并+100后,变为1220022,会对已遍历过的高位引入新的重复;此时再将遍历位回退2位重新遍历,即能解决进位带来的不稳定情况
总结一下,最终一步到位的算法步骤为:
1.将原数+1得到目标数字
2.对目标数字从高位向低位遍历,若未发现邻近重复数字,则转入步骤4;否则将2个重复数字中的低位数字+1,并记录重复处之后的低位位数
3.遍历位置回退2,重复步骤2
4.若记录了重复处之后的低位位数,则将这些低位用0、1相间的序列进行填充;返回修改后的目标数字
顺便附上输入数据为整形时的代码(c++字符串的代码有点长就不贴了):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | unsigned int GetNotRepeatNum(unsigned int lValue){ int temp, aim = lValue + 1; int divide = pow(10.0f, int(log10(double(aim))) - 1); while (divide >= 1){ temp = (aim / divide) % 10; if (temp == (aim / (divide * 10)) % 10){ aim = (aim / divide + 1) * divide; if (temp == 9){ divide *= 100; } }else{ divide /= 10; } } return aim; } |
最后发现自己实在是太罗嗦了,其实本篇就是一道可以用一句话来概括的水题,“高位到低位扫描,遇到相邻位相同,低位+1,低位后面的全置为0;重复上述直至十位与个位不同”,当然也可以用三个字,“构造法”
最近一段时间也是老夫聊发少年狂,刷了些oj,弥补以前的遗憾;不过也只能从实效性下手,无暇追求排名与AC数了。新手上道,挫折无限,还需多多修炼
3 条评论
教主你lvalue<100000判断没加0.0
哦纱布,小于100000是对输入的要求,不是对输出的要求
哦。。教主的意思是上面那个算作一个函数- -。