数字哑谜和回文游戏

编程之美4.10的两道题。

第一题:找出符合条件的九位数,每位数互不相同(1~9的某个排列),满足高n位能被n整除。例如abcdefghi,高两位ab能被2整除,高三位abc能被3整除,以此类推。

一提到排列,很容易就想到递归+回溯,这个方法在面试中使用频率相当高。1~9这九个数字做一次全排列,符合条件的打印,不符合条件的返回。这里可以使用一些剪枝,例如第二高位只能是偶数,第四高位只能是偶数,第五高位只能被5整除,第六高位只能是偶数,第八高位只能是偶数,这样的剪枝大大提高了程序的性能。

<span style="font-size:14px;">void FinANumber(char a[], int len, int index)
{
	// 第二个数必须是偶数
	if (index == 1 && (a[index] - '0') % 2 != 0)
		return;
	// 第四个数必须是偶数
	if (index == 3 && (a[index] - '0') % 2 != 0)
		return;
	// 第五个数必须是5的倍数
	if (index == 4 && (a[index] - '0') % 5 != 0)
		return;
	// 第六个数必须是偶数
	if (index == 5 && (a[index] - '0') % 2 != 0)
		return;
	// 第八个数必须是偶数
	if (index == 7 && (a[index] - '0') % 2 != 0)
		return;
	if (index == len)
	{
		for (int i = 0; i < len; i++)
		{
			// 前n个数必须被n整除
			int n = 0;
			for (int j = 0; j <= i; j++)
				n = n * 10 + a[j] - '0';
			if (n % (i + 1) != 0)
				return;
		}
		for (int i = 0; i < len; i++)
			cout << a[i];
		cout << endl;
		return;
	}

	// 递归+回溯
	for (int i = index; i < len; i++)
	{
		char tmp = a[index];
		a[index] = a[i];
		a[i] = tmp;

		FinANumber(a, len, index + 1);

		tmp = a[index];
		a[index] = a[i];
		a[i] = tmp;
	}
}

int main()
{
	char a[] = "123456789";

	FinANumber(a, 9, 0);

	system("pause");
	return 0;
}</span>

第二题:abcde * f = edcba,找出这样的abcdef五个数。

穷举法。使用一个1~9的哈希表可以记录哪些数已经被使用,哪些数未被使用,从而判断是否符合题意。

<span style="font-size:14px;">// 回文游戏
void Palindrome()
{
	bool isUsed[10];
	for (int n = 10000; n < 100000; n++)
	{
		bool flag = true;
		int copy = n;
		memset(isUsed, 0, sizeof(isUsed));
		int reverseNum = 0;

		// 循环求n的反转数
		for (int i = 0; i < 5; i++)
		{
			int tmp = copy % 10;
			reverseNum = reverseNum * 10 + tmp;
			copy /= 10;

			if (isUsed[tmp])
			{
				flag = false;
				break;
			}
			else
				isUsed[tmp] = true;
		}

		if (flag && (reverseNum % n == 0))
		{
			int x = reverseNum / n;
			if (x < 10 && !isUsed[x])
				cout << n << "*" << x << "=" << reverseNum << endl;
		}
	}
}

int main()
{
	Palindrome();

	system("pause");
	return 0;
}</span>


参考:
《编程之美》4.10

点赞