每日一题(97) - 找出大于某值的最小的不重复数

题目来自百度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,即90099nLastBit也指向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;
}

你可能感兴趣的:(每日一题(97) - 找出大于某值的最小的不重复数)