最大匹配算法 (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 题目解 ...
随机推荐
- centos 升级nginx到1.10.2
之前装的是1.6.3版本,准备升级到1.10.2版本. 1.下载nginx1.10.2 wget http://nginx.org/download/nginx-1.10.2.tar.gz 2.解压缩 ...
- PHP分页及原理
在看本文之前,请确保你已掌握了PHP的一些知识以及MYSQL的查询操作基础哦. 作为一个Web程序,经常要和不计其数的数据打交道,比如会员的数据,文章数据,假如只有几十个会员那很好办,在一页显示就可以 ...
- java 2017/6/26杂记
mkdirs()可以建立多级文件夹, mkdir()只会建立一级的文件夹, 如下: new File("/tmp/one/two/three").mkdirs(); 执行后, 会建 ...
- CF1137F Matches Are Not a Child's Play(LCT思维题)
题目 CF1137F 很有意思的题目 做法 直接考虑带修改的做法,上一次最大值为u,这次修改v,则最大值为v了 我们发现:\(u-v\)这条链会留到最后,序列里的其他元素相对位置不变,这条链会\(u\ ...
- Python3.x:pytesseract识别率提高(样本训练)
Python3.x:pytesseract识别率提高(样本训练) 1,下载并安装3.05版本的tesseract 地址:https://sourceforge.net/projects/tessera ...
- Object的各种方法
Object的一些知识点总结 1.hasOwnProperty obj.hasOwnProperty(prop) 参数 prop: 要检测的属性字符串名称或者Symbol 返回值 用来判断一个对象是否 ...
- 20145301Java课程总结
20145301 Java课程总结 每周读书笔记链接汇总 第一周读书笔记: http://www.cnblogs.com/5301z/p/5248888.html 第二周读书笔记: http://ww ...
- git revert
1. 我认为这是正确的做法: git fetch --all git reset --hard origin/master git fetch下载远程最新的,但不尝试,或重订任何东西. 然后,git ...
- Mysql CASE WHEN 用法
select sum(1) as col_0_0_, sum(case vciinfo.useable when -1 then 1 else 0 end) as col_1_0_, sum(case ...
- jar包中使用log4j2不起作用
某程序中有使用到log4j2,将该程序打包成jar,使用以下命令执行时,发现log4j不输出 java -cp Tool.jar com.zhen.nameOnce.Log4jTest 且报以下错误 ...