题意:有一串仅包含0和1的字符串(最长为200,000),统计长度在[A, B]的模式出现的次数(1<=A, B<=12),并将出现次数前N(1<=N<=50)的模式打印。长度为2的模式有00,01,10,11。
解题思路:
- 用一个树来表示字符串,左子树表示0,右子树表示1。类似Trie树。字符串用根节点到某一节点的路径来表示,如第三层最左边的字符串代表000,第三层第二个字符串代表001。因为最长的模式有12个字符,那么这棵树最多有13层,总结点数最多为2^13-1 = 8191个,所以这个完全二叉树可以由一个数组tree来表示,tree[i] = j代表i号节点代表的模式出现过j次。如果我没讲清楚可以搜索“Trie树”。
- 对[A, B]长度进行遍历,针对某一长度len,从头遍历一遍主串s,并将找到的s[i....i+len-1]转换为tree中相应的节点index。这个index初始化为0,遍历找到的s[i ... i+len-1],如果字符为0则index = index * 2 + 1,如果字符为1则index = index * 2 + 2。最终将tree[index]++。
- 遍历完后这个tree数组中存储的就是长度在[A, B]中的每种模式出现的次数。
- 对tree进行后续的处理即可输出最后的结果,逻辑不难,就是有点繁琐,在此不赘述。我用的是最简单的查找方式,因为需要的N不是很大,所以最终时间是够的。
代码:
/*
ID: zc.rene1
LANG: C
PROG: contact
*/
#include<stdio.h>
#include<string.h>
void PrintNum(int num, FILE *fout)
{
char s[13];
int index = 0, i;
memset(s, 0, 13*sizeof(char));
while (num != 0)
{
if (num % 2 == 0)
{
s[index++] = '1';
num = (num - 1) / 2;
}
else
{
s[index++] = '0';
num = num / 2;
}
}
for (i=index-1; i>=0; i--)
{
fprintf(fout, "%c", s[i]);
}
}
int main(void)
{
FILE *fin, *fout;
char main_string[200000];
int tree[8192];
int has_visited[8192];
int pow_of_two[14];
int A, B, N, index = 0;
int i, j, len, temp_index;
fin = fopen("contact.in", "r");
fout = fopen("contact.out", "w");
/*get input*/
fscanf(fin, "%d %d %d", &A, &B, &N);
memset(main_string, 0, 200000*sizeof(char));
while (fscanf(fin, "%s", main_string + index) != EOF)
{
index = strlen(main_string);
}
/*generate tree*/
memset(tree, 0, 8192*sizeof(int));
for (len=A; len<=B; len++)
{
for (i=0; i<=(index-len); i++)
{
temp_index = 0;
for (j=0; j<len; j++)
{
if (main_string[i+j] == '0')
{
temp_index = temp_index * 2 + 1;
}
else
{
temp_index = temp_index * 2 + 2;
}
}
tree[temp_index]++;
}
}
/*generate pow(2, n)*/
pow_of_two[0] = 1;
for (i=1; i<=13; i++)
{
pow_of_two[i] = (pow_of_two[i-1] * 2);
}
/*print the result*/
int has_print = 0;
memset(has_visited, 0, 8192*sizeof(int));
while (has_print < N)
{
int temp_max = -1;
for (i=pow_of_two[A]-1; i<=pow_of_two[B+1]-2; i++)
{
if ((has_visited[i] == 0) && (tree[i] > temp_max))
{
temp_max = tree[i];
}
}
if (temp_max <= 0)
{
break;
}
int temp_count = 0;
for (i=pow_of_two[A]-1; i<=pow_of_two[B+1]-2; i++)
{
if (tree[i] == temp_max)
{
has_visited[i] = 1;
if (temp_count == 0)
{
fprintf(fout, "%d\n", temp_max);
PrintNum(i, fout);
temp_count++;
}
else if (temp_count % 6 == 0)
{
fprintf(fout, "\n");
PrintNum(i, fout);
temp_count++;
}
else
{
fprintf(fout, " ");
PrintNum(i, fout);
temp_count++;
}
}
}
fprintf(fout, "\n");
has_print++;
}
return 0;
}