bm算法代码java实现 bm算法c语言

如何解决bitmap 内存溢出out of memory的问题

用BitmapFactory解码一张图片时,有时会遇到该错误。这往往是由于图片过大造成的。解决的方法可以考虑减少bitmap所需要的的空间。具体的解决办法是修改采样值BitmapFactory.Options.inSampleSize

德城ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为成都创新互联公司的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18980820575(备注:SSL证书合作)期待与您的合作!

BitmapFactory.Options opts = new BitmapFactory.Options();

opts.inJustDecodeBounds = true;

Bitmap bitmap = BitmapFactory.decodeFile(imageFile, opts);

设置inJustDecodeBounds为true后,decodeFile并不分配空间,但可计算出原始图片的长度和宽度,即opts.width和opts.height。有了这两个参数,再通过一定的算法,即可得到一个恰当的inSampleSize。

opts.inSampleSize = computeSampleSize(opts, -1, 128*128);

opts.inJustDecodeBounds = false;

try {

Bitmap bmp = BitmapFactory.decodeFile(imageFile, opts);

imageView.setImageBitmap(bmp);

} catch (OutOfMemoryError err) {

}

这样的话,就可以达到减少需要空间的目的了。

另外你也可以考虑释放bitmap已经被使用的空间从而达到增加空间的目的。

自然语言处理中的N-Gram模型详解

N-Gram(有时也称为N元模型)是 自然语言 处理中一个非常重要的概念,通常在NLP中,人们基于一定的语料库,可以利用N-Gram来预计或者评估一个句子是否合理。另外一方面,N-Gram的另外一个作用是用来评估两个字符串之间的差异程度。这是模糊匹配中常用的一种手段。本文将从此开始,进而向读者展示N-Gram在自然语言处理中的各种powerful的应用。

基于N-Gram模型定义的字符串距离

利用N-Gram模型评估语句是否合理

使用N-Gram模型时的数据平滑算法

欢迎关注白马负金羁的博客 ,为保证公式、图表得以正确显示,强烈建议你从该地址上查看原版博文。本博客 主要关注方向 包括:数字图像处理、 算法 设计与分析、 数据结构 、 机器学习 、数据挖掘、统计分析方法、自然语言处理。

基于N-Gram模型定义的字符串距离

在自然语言处理时,最常用也最基础的一个操作是就是“模式匹配”,或者称为“字符串查找”。而模式匹配(字符串查找)又分为 精确匹配 和 模糊匹配 两种。

所谓精确匹配,大家应该并不陌生,比如我们要统计一篇文章中关键词 “ information ” 出现的次数,这时所使用的方法就是精确的模式匹配。这方面的算法也比较多,而且应该是计算机相关专业必修的基础课中都会涉及到的内容,例如KMP算法、BM算法和BMH算法等等。

另外一种匹配就是所谓的模糊匹配,它的应用也随处可见。例如,一般的文字处理软件(例如,Microsoft Word等)都会提供拼写检查功能。当你输入一个错误的单词,例如 “ informtaion ” 时,系统会提示你是否要输入的词其实是 “ information ” 。将一个可能错拼单词映射到一个推荐的正确拼写上所采用的技术就是模糊匹配。

模糊匹配的关键在于如何衡量两个长得很像的单词(或字符串)之间的“差异”。这种差异通常又称为“距离”。这方面的具体算法有很多,例如基于编辑距离的概念,人们设计出了 Smith-Waterman 算法和Needleman-Wunsch 算法,其中后者还是历史上最早的应用动态规划思想设计的算法之一。现在Smith-Waterman 算法和Needleman-Wunsch 算法在生物信息学领域也有重要应用,研究人员常常用它们来计算两个DNA序列片段之间的“差异”(或称“距离”)。甚至于在LeetCode上也有一道 “No.72 Edit Distance” ,其本质就是在考察上述两种算法的实现。可见相关问题离我们并不遥远。

N-Gram在模糊匹配中的应用

事实上,笔者在新出版的 《算法之美——隐匿在数据结构背后的原理》 一书中已经详细介绍了包括Needleman-Wunsch算法、Smith-Waterman算法、N-Gram算法、Soundex算法、Phonix算法等在内的多种距离定义算法(或模糊匹配算法)。而今天为了引出N-Gram模型在NLP中的其他应用,我们首先来介绍一下如何利用N-Gram来定义字符串之间的距离。

我们除了可以定义两个字符串之间的编辑距离(通常利用Needleman-Wunsch算法或Smith-Waterman算法)之外,还可以定义它们之间的N-Gram距离。N-Gram(有时也称为N元模型)是自然语言处理中一个非常重要的概念。假设有一个字符串 s

,那么该字符串的N-Gram就表示按长度 N 切分原词得到的词段,也就是 s

中所有长度为 N 的子字符串。设想如果有两个字符串,然后分别求它们的N-Gram,那么就可以从它们的共有子串的数量这个角度去定义两个字符串间的N-Gram距离。但是仅仅是简单地对共有子串进行计数显然也存在不足,这种方案显然忽略了两个字符串长度差异可能导致的问题。比如字符串 girl 和 girlfriend,二者所拥有的公共子串数量显然与 girl 和其自身所拥有的公共子串数量相等,但是我们并不能据此认为 girl 和girlfriend 是两个等同的匹配。

为了解决该问题,有学者便提出以非重复的N-Gram分词为基础来定义 N-Gram距离这一概念,可以用下面的公式来表述:

|GN(s)|+|GN(t)|−2×|GN(s)∩GN(t)|

此处,|GN(s)|

是字符串 s

的 N-Gram集合,N 值一般取2或者3。以 N = 2 为例对字符串Gorbachev和Gorbechyov进行分段,可得如下结果(我们用下画线标出了其中的公共子串)。

有兴趣的读者可以在引用相关JAR包之后在Eclipse中执行上述Java程序,你会发现,和我们预期的一样,字符串Gorbachev和Gorbechyov所得之距离评分较高(=0.7),说明二者很接近;而girl和girlfriend所得之距离评分并不高(=0.3999),说明二者并不很接近。

利用N-Gram模型评估语句是否合理

从现在开始,我们所讨论的N-Gram模型跟前面讲过N-Gram模型从外在来看已经大不相同,但是请注意它们内在的联系(或者说本质上它们仍然是统一的概念)。

为了引入N-Gram的这个应用,我们从几个例子开始。首先,从统计的角度来看,自然语言中的一个句子 s

可以由任何词串构成,不过概率 P(s)

有大有小。例如:

s1

= 我刚吃过晚饭

s2

= 刚我过晚饭吃

显然,对于中文而言 s1

是一个通顺而有意义的句子,而s2

则不是,所以对于中文来说,P(s1)P(s2)

。但不同语言来说,这两个概率值的大小可能会反转。

其次,另外一个例子是,如果我们给出了某个句子的一个节选,我们其实可以能够猜测后续的词应该是什么,例如

the large green __ . Possible answer may be “mountain” or “tree” ?

Kate swallowed the large green __ . Possible answer may be “pill” or “broccoli” ?

显然,如果我们知道这个句子片段更多前面的内容的情况下,我们会得到一个更加准确的答案。这就告诉我们,前面的(历史)信息越多,对后面未知信息的约束就越强。

如果我们有一个由 m

个词组成的序列(或者说一个句子),我们希望算得概率 P(w1,w2,⋯,wm)

,根据链式规则,可得

P(w1,w2,⋯,wm)=P(w1)P(w2|w1)P(w3|w1,w2)⋯P(wm|w1,⋯,wm−1)

这个概率显然并不好算,不妨利用马尔科夫链的假设,即当前这个词仅仅跟前面几个有限的词相关,因此也就不必追溯到最开始的那个词,这样便可以大幅缩减上诉算式的长度。即P(wi|w1,⋯,wi−1)=P(wi|wi−n+1,⋯,wi−1)

特别地,对于 n

取得较小值的情况当 n=1

, 一个一元模型(unigram model)即为P(w1,w2,⋯,wm)=∏i=1mP(wi)

当 n=2

, 一个二元模型(bigram model)即为P(w1,w2,⋯,wm)=∏i=1mP(wi|wi−1)

当 n=3

, 一个三元模型(trigram model)即为P(w1,w2,⋯,wm)=∏i=1mP(wi|wi−2wi−1)

接下来的思路就比较明确了,可以利用最大似然法来求出一组参数,使得训练样本的概率取得最大值。

对于unigram model而言,其中c(w1,..,wn)

表示 n-gram w1,..,wn

在训练语料中出现的次数,M

是语料库中的总字数(例如对于 yes no no no yes 而言,M=5

)P(wi)=C(wi)M

对于bigram model而言,P(wi|wi−1)=C(wi−1wi)C(wi−1)

对于n

-gram model而言,P(wi|wi−n−1,⋯,wi−1)=C(wi−n−1,⋯,wi)C(wi−n−1,⋯,wi−1)

来看一个具体的例子,假设我们现在有一个语料库如下,其中s1s2

是句首标记,/s2/s1

是句尾标记:

s1s2yesnonononoyes/s2/s1s1s2nononoyesyesyesno/s2/s1

下面我们的任务是来评估如下这个句子的概率:s1s2yesnonoyes/s2/s1

我们来演示利用trigram模型来计算概率的结果P(yes|s1s2)=12,P(no|s2yes)=1P(no|yesno)=12,P(yes|nono)=25P(/s2|noyes)=12,P(/s1|yes/s2)=1

所以我们要求的概率就等于:12×1×12×25×12×1=0.05

再举一个来自文献[1]的例子,假设现在有一个语料库,我们统计了下面一些词出现的数量

下面这个概率作为其他一些已知条件给出:P(i|s)=0.25P(english|want)=0.0011P(food|english)=0.5P(/s|food)=0.68

,则可以算得P(s1)=P(i|s)P(want|i)P(english|want)P(food|english)P(/s|food)=0.25×0.33×0.0011×0.5×0.68=0.000031

使用N-Gram模型时的数据平滑算法

有研究人员用150万词的训练语料来训练 trigram 模型,然后用同样来源的 测试 语料来做验证,结果发现23%的 trigram 没有在训练语料中出现过。这其实就意味着上一节我们所计算的那些概率有空为 0,这就导致了数据稀疏的可能性,我们的表3中也确实有些为0的情况。对语言而言,由于数据稀疏的存在,极大似然法不是一种很好的参数估计办法。

这时的解决办法,我们称之为“平滑技术”(Smoothing)或者 “减值” (Discounting)。其主要策略是把在训练样本中出现过的事件的概率适当减小,然后把减小得到的概率密度分配给训练语料中没有出现过的事件。实际中平滑算法有很多种,例如:▸ Laplacian (add-one) smoothing▸ Add-k smoothing▸ Jelinek-Mercer interpolation▸ Katz backoff▸ Absolute discounting▸ Kneser-Ney

对于这些算法的详细介绍,我们将在后续的文章中结合一些实例再来进行讨论。

A Final Word

如果你能从前面那些繁冗、复杂的概念和公式中挺过来,恭喜你,你对N-Gram模型已经有所认识了。尽管,我们还没来得及探讨平滑算法(但它即将出现在我的下一篇博文里,如果你觉得还未过瘾的话),但是其实你已经掌握了一个相对powerful的工具。你可以能会问,在实践中N-Gram模型有哪些具体应用,作为本文的结束,主页君便在此补充几个你曾见过的或者曾经好奇它是如何实现的例子。

Eg.1 搜索引擎 (Google或者Baidu)、或者输入法的猜想或者提示。你在用百度时,输入一个或几个词,搜索框通常会以下拉菜单的形式给出几个像下图一样的备选,这些备选其实是在猜想你想要搜索的那个词串。再者,当你用输入法输入一个汉字的时候,输入法通常可以联系出一个完整的词,例如我输入一个“刘”字,通常输入法会提示我是否要输入的是“刘备”。通过上面的介绍,你应该能够很敏锐的发觉,这其实是以N-Gram模型为基础来实现的,如果你能有这种觉悟或者想法,那我不得不恭喜你,都学会抢答了!

Eg.2 某某作家或者语料库风格的文本自动生成。这是一个相当有趣的话题。来看下面这段话(该例子取材自文献【1】):

“You are uniformly charming!” cried he, with a smile of associating and now and then I bowed and they perceived a chaise and four to wish for.

你应该还没有感觉到它有什么异样吧。但事实上这并不是由人类写出的句子,而是计算机根据Jane Austen的语料库利用trigram模型自动生成的文段。(Jane Austen是英国著名女作家,代表作有《傲慢与偏见》等)

再来看两个例子,你是否能看出它们是按照哪位文豪(或者语料库)的风格生成的吗?

This shall forbid it should be branded, if renown made it empty.

They also point to ninety nine point six billion dollars from two hundred four oh three percent of the rates of interest stores as Mexico and Brazil on market conditions.

答案是第一个是莎士比亚,第二个是华尔街日报。最后一个问题留给读者思考,你觉得上面两个文段所运用的n-gram模型中,n应该等于多少?

推荐阅读和参考文献:

[1] Speech and Language Processing. Daniel Jurafsky James H. Martin, 3rd. Chapter 4[2] 本文中的一些例子和描述来自 北京大学 常宝宝 以及 The University of Melbourne “Web Search and Text Analysis” 课程的幻灯片素材

字符串匹配算法的使用(未完待整理)

字符串的匹配在Java中都知道使用indexOf函数来实现,那么其匹配算法是怎么样的呢?

单模式和多模式的区别就是一次遍历主串能否将多个模式的字符串都查找出来。

英文全称为Brute Force,暴力匹配算法,匹配字符串的方法比较暴力,也比较简单易懂。其大概的思路就是:

我们可以看到,在极端情况下,在主串 aaaa...aab 中寻找模式串 aab ,那么总共需要寻找(n-m+1)次,且每次都需要比对m次,那么时间复杂度将是 (n-m+1)*m ,即 O(n*m) ;但实际上并不会这么低效,因为我们的使用场景中主串和模式串都不会太长,而且在每个子串和模式串进行比对时,只要中途有一个不匹配,那么当前比对就会提前结束,因此大部分情况下,时间复杂度都会比 O(n*m) 要好。

我们在BF算法的基础上引入哈希算法,我们不需要将每个子串与模式串逐个字符地进行比较,而是计算得出每个子串的hash值,然后和模式串的hash值进行比较,如果有相等的,那就说明有子串和模式串匹配上了。

虽然我们只需要比对模式串和子串的hash值就能得到匹配结果,次数为(n-m+1),但是对每个子串进行hash计算的时候,是要遍历每个字符的,因此次数也是m,那么总的时间复杂度还是 O(n*m) ,并没有明显地提升。

那么我们该如何想出一个办法,使得每个子串hash值的计算时间得到提升呢?这就是RK算法的精髓,假设子串包含的字符集中元素个数为k,那么就用k进制数来代表这个子串,然后hash的过程就是将这个k进制的数转换为十进制的数,这个十进制的数就是该子串的hash值。

相邻子串的hash值计算是有规律的,我们只需要遍历一次主串就能得到所有子串的hash值,算法复杂度为O(n),而不是像原先一样,每个子串都需要O(m)的时间复杂度。

然后将模式串的hash值和所有子串的hash值进行比较,每次比较的时间复杂度是 O(1) ,总共比较(n-m+1)次,所以RK算法的总的时间开销为 O(n)+O(1)*O(n-m+1) ,即为 O(n) ,时间复杂度比BF算法更加高效。

当然,有hash的地方就有可能会存在hash冲突,有可能子串和hash值和模式串的hash值是一样的,但内容就是不一样,此时怎么办呢?其实很简单,对于hash值一样的子串,我们增加双保险,再比较一下这m个字符是否都一样即可,总的时间开销为 O(n)+O(1)*O(n-m+1)+O(m) ,即为 O(n) 。

如果极端情况下出现了很多hash冲突呢?我们对于每个和模式串相同hash值的子串都需要逐一再进行比较,那么总的时间开销就会为 O(n)+O(1)*O(n-m+1)+O(m)*O(n-m+1) ,即为 O(n*m) ,不过这种概率太小了,大部分情况下都不会这样。

在真正的文本编辑器中查找和替换某个字符串时,使用的算法既不是上述的BF算法,也不是RK算法;BF算法只适合不是很长的主串,RK算法则要设计一个冲突概率很低的hash算法,这个比较困难,所以实际使用的是BM算法,它是工程中非常常用的一种字符串匹配算法,效率也是最高的。

算法的思想和过程有些复杂,待以后整理。

KMP算法在本质上是和BM算法一样的。算法的思想和过程有些复杂,待以后整理。

浏览器输入框中的智能输入匹配是怎么实现的,它是怎么做动态字符串匹配查找的呢?这就用到了Trie树。

又名字典树,是一种专门用来快速查找字符串前缀匹配结果的树形结构,其本质就是将所有字符串的重复的前缀合并在一起,构造一个多叉树。

其中,根节点不包含任何信息,每个节点表示一个字符,从根节点到红色节点的一条路径表示存储的一个字符串。当我们在如上Trie树中查找"he"时,发现"he"并非是一个字符串,而是"hello"和"her"的公共前缀,那么就会找到这两个字符串返回。

Trie树在内存中是如何存储的呢?因为每一个节点都可能是包含所有字符的,所以每一个节点都是一个数组(或者散列表),用来存储每个字符及其后缀节点的指针。

使用Trie树,最开始构建的时候,时间复杂度为 O(n) ,其中n为所有字符串长度之和,但是一旦构建完成,频繁地查询某个字符串是非常高效的,时间复杂度为 O(k) ,其中k为查找字符串的长度。

Trie树虽然查询效率很高,但是比较浪费内存,每一个节点都必须维护一个数组存放所有可能的字符数据及其指向下一个节点的指针,因此在所有字符串公共前缀并不多的时候,内存空间浪费地就更多了。这种问题其实也有对应的解决办法,我们可以不使用数组,而是使用有序数组、散列表、红黑树来存放,可以相应地降低性能来节省内存空间。

Trie树除了可以实现浏览器动态输入内容查找候选项的功能外,还可以实现多模式地敏感词匹配功能。假设我们需要对用户输入的内容进行敏感词检查,将所有的敏感内容用***代替,那么该如何实现呢?

首先我们可以维护一个敏感词字典,使用上述四种单模式匹配算法也可以实现,但是需要遍历N次用户输入的内容,其中N是所有敏感词的模式串,显得非常低效。但是我们如果将敏感词字典维护为一个Trie树,然后将用户输入的内容从位置0开始在Trie树中进行查询,如果匹配到红色节点,那么说明有敏感词;如果没有匹配到红色节点,就从用户输入内容的下一个位置开始继续在Trie树中查询,直至将用户输入内容遍历完,因此我们只是遍历了一遍主串。

然而更高效的多模式字符串匹配使用地更多的是如下的AC自动机。

如果把Trie树比作BF算法,KMP算法是BF算法的改进,那么AC自动机就是利用同样的思想改进了Trie树。

算法的思想和过程有些复杂,待以后整理。


当前题目:bm算法代码java实现 bm算法c语言
网站路径:http://azwzsj.com/article/dddposd.html