被遗漏的数字(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;
}