求比指定数大且最小的“不重复数”

题目:

给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数”的含义是相邻两位不相同,例如1101是重复数,而1201是不重复数。(百度2014校招笔试题目)

解法一:(普通,低效)

思路:

这道题目我也没有什么特别出彩的算法,就是按照常规思路来求解,首先要理解什么叫做“不重复数”,这是解题的关键之一,相邻两位不相同的数即为“不重复数”;还有一个地方要注意的就是“求比这个数大且最小的”,就是在比给定数大的不重复数中找到最小的!理解了这两个地方,这道题目就可以着手求解了!

我用一个实例来说说我的思路,加入给定的正整数为11233:

用最常规的方法,就是每次对这个数加1,判断是不是“不重复数”,加1后为11234,有两个1重复了,于是继续加1,……,那么主要就在判断是不是“不重复数”上面了,我设置了两个变量,是currentBit, lastBit,顾名思义,lastBit保存上一个数位的值,currentBit保存当前数位的值,拿整数12345来说,就是初始化lastBit = 5,然后计算currentBit = 4;下一步,把currentBit 值赋给lastBit,即lastBit = 4,计算currentBit  = 3;依次类推。

说到这里,很多朋友觉得可以有更加高效的方法,小难点有4:

1、因为可以直接定位到“重复”的数位那里,比如12344,我们可以直接定位到个位数4和十位数4上面,然后在低位数(这里就是个位数)上加1即可,事实上,不是如此简单,假设是对整数12199呢?还能简单的加1操作吗,加1之后结果为12200,那结果显然是错的,当然这也是可以处理的,处理方法就是把12200继续拿到循环去判断是不是“非重复数”;

2、这里又产生一个问题,因为“重复“的数位可能不止一对,有可能有多对,比如整数11233,定位“33”之后变为“34”,定位“11”之后变为“12”,结果就是12234。又有重复的地方,就是“22”。继续拿到循环去重复;

3、还有要注意的是,你的程序设计,是如何存储数位的值的,是一个一个数位的值求出来呢?还是像我这样设置一个前后索引?每个数位取值,程序会变得繁琐复杂,不易读懂,如果是设置前后索引,则要注意程序退出循环的条件!

4、对于存在多对“重复”数位的正整数,数位“重复”的定位和变换,是从高位到低位,还是从低位到高位呢?正确的应该是从高位到低位,这与我们的程序设计也带来了不便。

/*
    给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数的含义是相邻两位不相同,例如1101是不重复数”
*/
#include <stdio.h>
#include <stdlib.h>
int getNumNonrepetition(const int NumGived)
{
    int flag = 0;//为0表示该数不是“不重复数”
    int numRepeat = NumGived;
    int numTemp = 0;//
    int currentBit = 0, lastBit = 0;//前后数位索引
    while(1)
    {
        numRepeat++;
        //初始化后索引
        numTemp = numRepeat;
        lastBit = numTemp % 10;
        numTemp /= 10;
        flag = 1;
        //判断该数是不是“非重复数”
        while(numTemp != 0)
        {
            currentBit = numTemp % 10;
            numTemp /= 10;
            if(lastBit == currentBit)
            {
                flag = 0;
                break;
            }
            lastBit = currentBit;
        }
        if(flag == 1)//该数为不重复数,返回
        {
            return numRepeat;
        }
    }
}
int main(void)
{
    int NumGived = 19922884;
    int result = getNumNonrepetition(NumGived);
    printf("the number is %d\n", result);
    return 0;
}

结果:

QQ截图20140303100726

 

解法二:(高效)

思路:

1、把整数放到字符数组里面去,从高位为低位(用变量i)扫描,找到重复的数位,重复数位为“99”跳到第2步,否则跳到第3步,若没有重复的数位,则该数为不重复数,返回;

2、遇到“99”的重复数,则把“99”改为“00”,然后在“99”前面一位字符加1,把扫描的地方定位在“99”往高位方向的第2位,比如是1299,变换后为1300,然后把扫描变量 i 定位在1这一数位上,返回第1步;

3、遇到非“99”的重复数,则直接在低位加1,后面依次变为010101……,结果就是最小的不重复数,返回改值;

代码:

#include <iostream>
#include <cstdlib>
#define MAX_NUM 100
using namespace std;
void  getNonrepeatNumber(const long long val);
int main(void)
{
	long long val = 121;
	getNonrepeatNumber(val);
	return 0;
}
void getNonrepeatNumber(const long long val)
{
	char buf[MAX_NUM];
	memset(buf, '0', sizeof(char)*MAX_NUM);
	sprintf(buf+1, "%lld", val);//第一个位置空掉,用来保存进位 
	int len = strlen(buf);
	cout<<"原数为:"<<buf+1<<endl;
	int i = 1;
	bool first = true;
	while(true)
	{
		while(i + 1 < len && buf[i] != buf[i+1])
			i++;
		//如果是第一次扫描发现原数本身就是一个不重复数,则在其最低位+1
		//+1时进行判断,如果个位为9,则变为0,再进位,否则直接+1 
		//+1后判断会不会跟前一位重复 
		
		if( (i == len - 1) && first)
		{
			if(buf[i] == '9')
			{
				buf[i] =  '0';
				i--;				
			}
			buf[i] += 1;
			i--;
			first = false;
			continue;			
		}
		//如果是第二次扫描到此,则直接退出,表示当前数为最小不重复数 
		else if(i == len - 1)
			break;
		
		//重复的数位为99这种情况,将这两位全部置0,高位加1
		if(buf[i+1] == '9')
		{
			buf[i+1] = '0';
			i--;
			buf[i+1] = '0';
			i--;
			buf[i+1] += 1;
		}
		else
		{
			buf[i+1] += 1;
			i += 2;
			bool flag = true;
			//后续全部设为0101……,这个时候肯定是不重复数了,所以可以跳出循环
			while(i < len)
				if(flag)
				{				
					buf[i++] = '0';					
					flag = false;
				}
				else
				{
					buf[i++] = '1';
					flag = true;	
				}
					
					
			break;
		}
	}
	cout<<"最小不重复数为:"; 
	//如果是99开头的数字,高位可能会进位,判断是否为零,不为零则有进位,需打印出来
	if(buf[0] == '0')
		cout<<buf+1<<endl;
	else cout<<buf<<endl;
}

结果:

QQ截图20140303140914

QQ截图20140303140935

QQ截图20140303140957

QQ截图20140303141041

QQ截图20140303141017

posted @ 2014-03-03 14:13  mickole  阅读(591)  评论(0)    收藏  举报