二十一、前缀码判定
题目描述
前缀码:任何一个字符的编码都不是同一字符集中另一个字符的编码的前缀。
请编写一个程序,判断输入的n个由1和0组成的编码是否为前缀码。如果这n个编码是前缀码,则输出"YES”;否则输出第一个与前面编码发生矛盾的编码。
输入:
第1行为n(表示下面有n行编码)
第2~n+1行为n个由0或1组成的编码
**输出:**判断结果
例如,如果输入:
5
00
01
10
110
111
每一个字符均不是其他字符编码的前缀,所以,输出:YES
再如,如果输入:
5
00
01
10
110
11
编码11与前面的编码110的前缀,所以,输出:11
测试输入 | 期待的输出 | 时间限制 | 内存限制 | 额外进程 | |
---|---|---|---|---|---|
测试用例 1 | 5 00 01 10 110 111 | YES | 1秒 | 64M | 0 |
测试用例 2 | 5 00 01 10 110 11 | 11 | 1秒 | 64M | 0 |
测试用例 3 | 5 00 01 10 11 111 | 111 | 1秒 | 64M | 0 |
测试用例 4 | 5 111 110 10 01 00 | YES | 1秒 | 64M | 0 |
测试用例 5 | 8 00 010 0110 0111 10 110 1110 1111 | YES | 1秒 | 64M | 0 |
测试用例 6 | 8 00 010 0110 0111 10 11 1110 111 | 1110 | 1秒 | 64M | 0 |
解题思路
所谓前缀码的判定,本质上是二叉树的建树问题。令二叉树的左子树都代表1,遇到 1 都向左走;右子树都代表0,遇到 0 都向右走。
对于全新的没有前缀的字符编码,则二叉树中建立对应分支,分支除了最后一个结点外的所有结点值都为0,仅最后一个结点值为1。
字符编码是前缀码的话,如果在分支的行进过程中碰到值为 1 的结点,则当前字符编码存在前缀码;如果编码遍历完成,但是最后一个字符没有新建结点,则当前字符编码是别人的前缀码。
对于前缀码,我们用一个 flag 进行标记。当 flag 为 1 时表示存在前缀码,输出第一个前缀码 prefix。如果全部判断完成,flag 仍为0,则没有前缀码。
上机代码
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
typedef struct NODE
{
int data;
struct NODE *lchild;
struct NODE *rchild;
}node,*Tree;
int main()
{
int n = 0;
char str[100010], prefix[100010];
int flag = 0;
Tree bit, T;
bit = (Tree)malloc(sizeof(node));//初始化
bit->data = 0;
bit->lchild = NULL;
bit->rchild = NULL;
cin >> n;
while(n--)
{
memset(str, 0, sizeof(str));
cin >> str;
int len = strlen(str);
if (flag == 1) //存在前缀码后面都不用判断了,读取编码后直接跳出循环
continue;
strcpy(prefix, str);//保存第一个前缀码
T = bit;//每次变回根节点初始化状态
for (int i = 0; i < len; i++)
{
if (str[i] == '1') //1向左走
{
if (T->lchild == NULL)//左子树新建结点
{
T->lchild = (Tree)malloc(sizeof(node));
T = T->lchild;
T->lchild = NULL;
T->rchild = NULL;
if (i == len - 1)
T->data = 1;
else
T->data = 0;
}
else
{
if (T->lchild->data == 1 || i == len - 1)//存在前缀码
{
flag = 1;
break;
}
else
T = T->lchild;
}
}
else //0向右走
{
if (T->rchild == NULL)//右子树新建结点
{
T->rchild = (Tree)malloc(sizeof(node));
T = T->rchild;
T->lchild = NULL;
T->rchild = NULL;
if (i == len - 1)
T->data = 1;
else
T->data = 0;
}
else
{
if (T->rchild->data == 1 || i == len - 1)
{
flag = 1;
break;
}
else
T = T->rchild;
}
}
}
}
if (flag == 0)//没有前缀码
cout << "YES" << endl;
else
cout << prefix << endl;
//system("pause");
return 0;
}