2017年清华软院保研机试第3题:被遗漏的数字

被遗漏的数字(30 分)

Problem Description

小明写了一个函数,将1-n 的数随机排列组成一个字符串,每个数字使用且仅使用一次。但是小明在写的时候粗心了,导致生成的字符串丢失了其中一个数字。帮助小明找出这个数字

Input

测试输入包含若干测试用例,每个测试用例占两行,第一行是n(2<=n<=200),第二行是一个字符串。

Output

对每个测试用例输出1 行,输出缺漏的数字

Sample Input

5
1234
20
12345678910111314151617181920

Sample Output

5
12

--------------------------------------------------------------------------------

思路

统计1~n所有数码('0'~'9')中应该出现的次数,与实际字符串中出现的数码次数相减,得到被遗漏的数字的组成数码。如果组成数码中有0,需要特判。否则将数码组合成各种<=n的排列,统计各个排列在字符串中出现的次数。若一个排列在字符串中出现的次数小于其应该出现的次数,则被遗漏的数字就是这个排列。

一个未解决的问题是例如下面的输入:

21

1234567891011131415161718192021

既可以认为答案是12,也可以认为答案是21

--------------------------------------------------------------------------------

代码

主程序

#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>

void itos(int n, char *c_n)
{
	int i = 0, j =0;
	while (n > 0)
	{
		c_n[i++] = n%10 + '0';
		n /= 10;
	}
	for (j=0; j<i/2; j++)
	{
		std::swap(c_n[j], c_n[i-1-j]);
	}
	c_n[i] = '\0';
}

int cnt_times(char str[600], int ans)
{
	char c_ans[4];
	itos(ans, c_ans);
	bool match = true;
	int i, j, k, str_len = strlen(str), clen = strlen(c_ans), cnt = 0;
	for (i=0; i<=str_len - clen; i++)
	{
		match = true;
		k = i;
		for (j=0; j<clen; j++)
		{
			if (str[k+j] != c_ans[j])
			{
				match = false;
				break;
			}
			if (match)
			{
				cnt++;
			}
		}
	}
	return cnt;
}

int expect(int ans, int n)		// 两位数ans理应在1~n中出现的次数(n<=200),保证ans的两位不相同
{
	if (n < 100)
	{
		return 1;
	}
	else
	{
		int cnt = 0;
		if (100 + ans <= n)
		{
			cnt++;
		}
		for (int i=0; i<=9; i++)
		{
			if (ans*10+i<=n)
			{
				cnt++;
			}
			else
			{
				break;
			}
		}
		return cnt+1;
	}
}


int pick(char str[600], std::vector<int> select, int n)
{
	if (select.front() >= 100)			// 三位数只要没有出现就是“被遗漏的数字”
	{
		for (std::vector<int>::iterator it = select.begin(); it != select.end(); it++)
		{
			if (!cnt_times(str, *it))
			{
				return *it;
			}
		}
	}
	else								// 两位数要计算在字符串中应该出现的次数,出现次数小于它才是“被遗漏的数字”
	{
		for (std::vector<int>::iterator it = select.begin(); it != select.end(); it++)
		{
			if (cnt_times(str, *it) < expect(*it, n))
			{
				return *it;
			}
		}
	}
	return select.front();				// 对于未决情况,任意输出,不妨输出第一个组合
}


int main()
{
#ifndef ONLINE_JUDGE
	freopen("thuSE16_02.txt", "r", stdin);
#endif
	int n, i, j, a, str_len, len, ans1, ans2, ans3, ans4, ans5, ans6, myans;
	char str[600] = {};
	int cnt[10] = {};
	std::vector<int> ans;
	std::vector<int> select;				// 备选数字集合
	std::vector<int>::iterator it;
	while (scanf("%d", &n) != EOF)
	{
		memset(cnt, 0, sizeof(cnt));
		ans.clear();
		for (i=1; i<=n; i++)
		{
			a = i;
			while (a > 0)
			{
				cnt[a%10] ++;
				a /= 10;
			}
		}
		scanf("%s", str);
		str_len = strlen(str);
		for (i=0; i<str_len; i++)
		{
			a = str[i] - '0';
			cnt[a]--;
		}
		for (i=0; i<=9; i++)
		{
			for (j=0; j<cnt[i]; j++)
			{
				ans.push_back(i);
			}
		}
		len = ans.size();
		if (len == 1)
		{
			printf("%d\n", ans.front());
		}
		else if (len == 2)
		{
			ans1 = ans.at(0)*10 + ans.at(1);
			ans2 = ans.at(1)*10 + ans.at(0);
			if (ans.at(0) == 0)
			{
				printf("%d\n", ans2);
			}
			else if (ans1 == ans2)
			{
				printf("%d\n", ans1);
			}
			else if (ans1 > n)
			{
				printf("%d\n", ans2);
			}
			else if (ans2 > n)
			{
				printf("%d\n", ans1);
			}
			else
			{
				select.clear();
				select.push_back(ans1);
				select.push_back(ans2);
				printf("%d\n", pick(str, select, n));
			}
		}
		else if (len == 3)
		{
			ans1 = 100*ans.at(0) + 10*ans.at(1) + ans.at(2);
			ans2 = 100*ans.at(0) + 10*ans.at(2) + ans.at(1);
			ans3 = 100*ans.at(1) + 10*ans.at(0) + ans.at(2);
			ans4 = 100*ans.at(1) + 10*ans.at(2) + ans.at(0);
			ans5 = 100*ans.at(2) + 10*ans.at(0) + ans.at(1);
			ans6 = 100*ans.at(2) + 10*ans.at(1) + ans.at(0);
			if (ans.at(0) == 0 && ans.at(1) == 0)
			{
				printf("%d\n", ans6);
			}
			else if (ans.at(0) == ans.at(1) == ans.at(2))
			{
				printf("%d\n", ans1);
			}
			else if (ans.at(0) == 0)
			{
				select.clear();
				select.push_back(ans3);
				select.push_back(ans4);
				select.push_back(ans5);
				select.push_back(ans6);
				myans = select.back();
				while (myans > n)
				{
					select.pop_back();
					myans = select.back();
				}
				printf("%d\n", pick(str, select, n));
			}
			else
			{
				select.clear();
				select.push_back(ans1);
				select.push_back(ans2);
				select.push_back(ans3);
				select.push_back(ans4);
				select.push_back(ans5);
				select.push_back(ans6);
				myans = select.back();
				while (myans > n)
				{
					select.pop_back();
					myans = select.back();
				}
				printf("%d\n", pick(str, select, n));
			}
		}
	}
	return 0;
}

对拍程序

#include<cstdio>
#include<cstdlib>
#include<algorithm>

int a[205] = {};

int main()
{
	int n = 150, i, r1, r2, t = 100;		// n: total number
	for (i=0; i<n; i++)
	{
		a[i] = i+1;
	}
	for (i=0; i<t; i++)
	{
		r1 = rand()%n;
		r2 = rand()%n;
		std::swap(a[r1], a[r2]);
	}
	FILE * fp = fopen("thuSE16_02.txt", "w");
	fprintf(fp, "%d\n", n);
	for (i=0; i<n; i++)
	{
		if (a[i] != 12)						// 12: missing number
		{
			fprintf(fp, "%d", a[i]);
		}
	}
	fclose(fp);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/82381617