最大匹配算法 (Maximum Matching)
之所以研究这个算法,是因为最近在研究NLP中文的分词,所谓分词就是将一个完整的句子,例如“计算语言学课程有意思”,分解成一些词组单元“计算语言学,课程,有,意思”。 “最大匹配法” 在中文分词中有所应用,因此这里介绍一下。
“最大匹配法” 分为正向匹配和逆向匹配,这里先看正向匹配。
算法思想:
正向最大匹配算法:从左到右将待分词文本中的几个连续字符与词表匹配,如果匹配上,则切分出一个词。但这里有一个问题:要做到最大匹配,并不是第一次匹配到就可以切分的 。我们来举个例子:
待分词文本: sentence[]={"计","算","语","言","学","课","程","有","意","思"}
词表: dict[]={"计算", "计算语言学", "课程", "有", "意思"} (真实的词表中会有成千上万个已经平时我们使用的分好的词语)
(1) 从sentence[1]开始,当扫描到sentence[2]的时候,发现"计算"已经在词表dict[]中了。但还不能切分出来,因为我们不知道后面的词语能不能组成更长的词(最大匹配)。
(2) 继续扫描content[3],发现"计算语"并不是dict[]中的词。但是我们还不能确定是否前面找到的"计算语"已经是最大的词了。因为"计算语"是dict[2]的前缀。
(3) 扫描content[4],发现"计算语言"并不是dict[]中的词。但是是dict[2]的前缀。继续扫描:
(3) 扫描content[5],发现"计算语言学"是dict[]中的词。继续扫描下去:
(4) 当扫描content[6]的时候,发现"计算语言学课"并不是词表中的词,也不是词的前缀。因此可以切分出前面最大的词——"计算语言学"。
由此可见,最大匹配出的词必须保证下一个扫描不是词表中的词或词的前缀才可以结束。
代码实现:
这里字典就临时这样简单写死,真实的情况需要构造一个hash,这样效率较高,我们看下算法的代码吧:
#include<iostream>
#include<string>
using namespace std; // 宏,计算数组个数
#define GET_ARRAY_LEN(array,len){len=(sizeof(array)/sizeof(array[0]));} string dict[] = {"计算", "计算语言学", "课程", "有", "意思"}; // 是否为词表中的词或者是词表中词的前缀
bool inDict(string str)
{
bool res = false;
int i;
int len = ; GET_ARRAY_LEN(dict, len); for (i = ; i<len; i++)
{
// 是否和词表词相等或者是词表词前缀
if( str == dict[i].substr(, str.length()))
{
res = true;
}
}
return res;
} int main()
{
string sentence = "计算语言学课程有意思";
string word = "一";
int wordlen = word.length(); int i;
string s1 = ""; for (i = ; i<sentence.length(); i = i+wordlen)
{
string tmp = s1 + sentence.substr(i, wordlen); if(inDict(tmp))
{
s1 = s1 + sentence.substr(i, wordlen);
}
else
{
cout<<"分词结果:"<<s1<<endl;
s1 = sentence.substr(i, wordlen);
}
}
cout<<"分词结果:"<<s1<<endl;
}
我在linux下运行的结果是:
可以看到分词的结果符合我们的预期,如果词表足够大,那么所有的句子都可以被分词。iao
接下来说下逆向的最大匹配算法。
算法思想:
逆向匹配算法大致思路是从右往左开始切分。我们还是用上面的例子:
待分词句子: sentence[]={"计算语言学课程有意思"}
词表: dict[]={"计算", "计算语言学", "课程", "有", "意思"}
首先我们定义一个最大分割长度5,从右往左开始分割:
(1) 首先取出来的候选词W是 “课程有意思”。
(2) 查词表,W不在词表中,将W最左边的第一个字去掉,得到W“程有意思”;
(3) 查词表,W也不在词表中,将W最左边的第一个字去掉,得到W“有意思”;
(4) 查词表,W也不在词表中,将W最左边的第一个字再去掉,得到W“意思”;
(5) 查词表,W在词表中,就将W从整个句子中拆分出来,此时原句子为“计算语言学课程有”
(6) 根据分割长度5,截取句子内容,得到候选句W是“语言学课程有”;
(7) 查词表,W不在词表中,将W最左边的第一个字去掉,得到W“言学课程有”;
(8) 查词表,W也不在词表中,将W最左边的第一个字去掉,得到W“学课程有”;
(9) 依次类推,直到W为“有”一个词的时候,这时候将W从整个句子中拆分出来,此时句子为“计算语言学课程”
(10) 根据分割长度5,截取句子内容,得到候选句W是“算语言学课程”;
(11) 查词表,W不在词表中,将W最左边的第一个字去掉,得到W“语言学课程”;
(12) 依次类推,直到W为“课程”的时候,这时候将W从整个句子中拆分出来,此时句子为“计算语言学”
(13) 根据分割长度5,截取句子内容,得到候选句W是“计算语言学”;
(14) 查词表,W在词表,分割结束。
代码实现:
#include<iostream>
#include<string>
using namespace std; // 宏,计算数组个数
#define GET_ARRAY_LEN(array,len){len=(sizeof(array)/sizeof(array[0]));} // 定义最大词长
#define MAX_WORD_LENGTH 5 string dict[] = {"计算", "计算语言学", "课程", "意思"}; // 是否为词表中的词
bool inDict(string str)
{
bool res = false;
int i;
int len = ; GET_ARRAY_LEN(dict, len); for (i = ; i<len; i++)
{
if( str == dict[i])
{
res = true;
}
}
return res;
} int main()
{
string sentence = "计算语言学课程有意思";
string word = "一";
int wordlen = word.length(); int i; for (i = ; i<sentence.length(); )
{
int dealstrbegin = sentence.length()-wordlen*MAX_WORD_LENGTH-i;
int dealstrlen = wordlen*MAX_WORD_LENGTH;
// 截取的要处理的字符串
string dealstr = sentence.substr(dealstrbegin, dealstrlen); int j;
for (j = ; j<MAX_WORD_LENGTH; j++)
{
int fb = j*wordlen;
int fl = wordlen*(MAX_WORD_LENGTH-j);
// 去掉签名的j个字
string tmp = dealstr.substr(fb, fl); if(inDict(tmp) || j==MAX_WORD_LENGTH- )
{
cout<<"分词结果:"<<tmp<<endl;
i=i+fl;
break;
}
}
}
}
代码运行的结果是:
最大匹配算法 (Maximum Matching)的更多相关文章
- [Codeforces Round #508 (Div. 2)][Codeforces 1038E. Maximum Matching]
前几天给舍友讲这题的时候感觉挺有意思的,就贴上来吧... 题目链接:1038E - Maximum Matching 题目大意:有\(n\)个棒子,每个条两端有颜色\(c1,c2\)以及他的价值\(v ...
- Codeforces 1038 E - Maximum Matching
E - Maximum Matching 思路: 欧拉图 定理:一个度数为奇数的点的个数小于等于2的联通图存在欧拉回路 对于这道题目的图,点的个数为4,所以最坏的情况下4个点的度数都为奇数,在这种情况 ...
- Codeforces Round #508 (Div. 2) E. Maximum Matching(欧拉路径)
E. Maximum Matching 题目链接:https://codeforces.com/contest/1038/problem/E 题意: 给出n个项链,每条项链左边和右边都有一种颜色(范 ...
- [codeforces 508E]Maximum Matching
题目:Maximum Matching 传送门:http://codeforces.com/contest/1038/problem/E 分析: 一个块拥有{color1,val,color2},两个 ...
- SPOJ4206Fast Maximum Matching(hopcroft-karp)
题目请戳这里 题目大意:裸的二分匹配. 题目分析:数据比较强,用来测模版的.这题用hungry跑着会比较吃力,所以用hopcroft-karp算法.这个算法较hungry高效是因为每次bfs找到一个增 ...
- SPOJ 4206 Fast Maximum Matching (二分图最大匹配 Hopcroft-Carp 算法 模板)
题目大意: 有n1头公牛和n2头母牛,给出公母之间的m对配对关系,求最大匹配数.数据范围: 1 <= n1, n2 <= 50000, m <= 150000 算法讨论: 第一反应 ...
- CF1038E Maximum Matching 搜索/区间DP
题目传送门:http://codeforces.com/problemset/problem/1038/E 题意:给出$N$个方块,每个方块有左右两种颜色$a,b$(可以翻转使左右两种颜色交换)和一个 ...
- CF#508 1038E Maximum Matching
---题面--- 题解: 感觉还是比较妙的,复杂度看上去很高(其实也很高),但是因为n只有100,所以还是可以过的. 考虑一个很暴力的状态f[i][j][x][y]表示考虑取区间i ~ j的方格,左右 ...
- Codeforces 1038E Maximum Matching
可能写了个假算法 假设定义:含有一个欧拉路的图为类欧拉图 欧拉路的定义:一个无向连通图中,存在一条路径对所有边都遍历且仅遍历一次:判断方法:该连通图中度为奇数的点的个数不能超过2,即为0或者2 题目解 ...
随机推荐
- javascript 理解对象--- 定义多个属性和读取属性的特性
一 定义多个属性 ECMAScript5 定义了一个Object.defineProperties()方法,用于定义多个属性.此方法接受两个对象参数: 第一个对象:要添加或修改其属性的对象 第二个对象 ...
- tensorflow中使用tf.variable_scope和tf.get_variable的ValueError
ValueError: Variable conv1/weights1 already exists, disallowed. Did you mean to set reuse=True in Va ...
- TOSCA自动化测试工具--识别元素唯一性的控件
当Modules模块通过Scan识别出页面元素后,选择需要测试的对象,然后判断对象唯一性
- ABP官方文档翻译 1.2 N层架构
N层架构 介绍 ABP架构 其他(通用) 领域层 应用层 基础设施层 网络和展现层 其他 总结 介绍 应用程序代码库的分层架构是被广泛认可的可以减少程序复杂度.提高代码复用率的技术.为了实现分层架构, ...
- WeX5基础
最近在研究微信app开发,使用的是WeX5,在这里把一些基础知识点记录下来,忘记了可以翻阅查看. 一:开发后端服务 1.建立数据源:窗口--首选项--studio配置--数据源--增加--数据源类型选 ...
- 如何安装python .whl包
1.最简单的办法是是python -mpip install *** 配置过环境变量也可以 pip install *** 但是由于墙的原因,很大概率失败.可以找到对应网站下载对应的.whl 2.下载 ...
- RocEDU.阅读.写作《乌合之众》(一)
序言 作者在序言里主要论述了时代演变的内在原因,表明对群体进行研究的重要性,阐述了研究群体行为特征时的研究方法,并概述了群体的发展过程. 造成文明变革的唯一重要变化,是影响到思想.观念和信仰的变化.目 ...
- linux中断的下半部机制
一.中断处理为什么要下半部?Linux在中断处理中间中断处理分了上半部和下半部,目的就是提高系统的响应能力和并发能力.通俗一点来讲:当一个中断产生,调用该中断对应的处理程序(上半部)然后告诉系统,对应 ...
- 广播机制的CS模型实现
广播机制的cs模型实现如下: 首先可以使用ifconfig命令查看自己所在网段的广播地址 server.c #include<stdio.h> #include<unistd.h&g ...
- 设置iframe内表单target属性以兼容IE、Firefox【转载】
设置iframe内表单target属性以兼容IE.Firefox[转载] 2011年11月19日 haibor 今天有客户反应,在一产品网站的资源下载页面,用户登录提交后页面无反应! 经测 ...