September 4, 2009

在之前的一个文里有谈及到过最长公共字序列的问题,这个可以用来衡量俩个序列的相似度。

今年的Goolge Code jam的qualification Round 也有一道类似的问题:

【Sub-Sequence-Match】x=[]是一序列,y=[]是另一序列:问x中共有多少个不同的子序列等于y

和这个问题有一点类似的问题是IJCAI07的一篇文里提到的:

【All-Common-Subquence】x=[]是一序列,y=[]是另一序列:问x,y共有多少个不同的公共子序列

想法还是DP:

For S-S-M:

def f(x,y):
    if len(x)<len(y):
        return 0
    if len(y)==1:
        count=0
        for k in x:
            if k==y:
                count=count+1
        return count
    a=len(x)
    b=len(y)
    if x[a-1]==y[b-1]:
        return f(x[0:a-1],y[0:b-1])+f(x[0:a-1],y[0:b])
    if x[a-1]!=y[b-1]:
        return f(x[0:a-1],y[0:b])

意思就是:
如果x长度比y小,那么返回0;如果长度y=1了,那么就看x串中有几个y,返回这个个数;
不然的话
如果最后一个元素相等,那么让x’为x去掉最后一个元素的序列,y’为y去掉最后一个元素序列:
返回s-s-m(x’,y’)+s-s-m(x’,y)

如果最后一个元素不等,那么直接返回s-s-m(x’,y)

当然可以把上面的递归改写成递推的,这样效率会大大提高,并且不改的话,Code jam的大数据肯定是要会TLE的,改写起来很简单就不写鸟。

再来看看A-C-S的DP,大家基本可以自己想想就可以解决了,和上面的思路很类似

N(i, j) = N(i − 1, j − 1) × 2, if Ai = Bj
N(i, j) = N(i − 1, j) + N(i, j − 1) − N(i − 1, j − 1),
if Ai!= Bj

如果最后的元素相同,实际就是前面的A-C-S(i-1,j-1)×2.(有或没有最后一个item作为CS的一部分)
不然的话等于下面那个,注意要扣除掉重复计算的A-C-S(i-1,j-1)

E-O-F

Tags: ,,.
August 12, 2009

Association Rule Learning是一种用来发掘目前的数据库里的变量之间潜在的关系的例子,这里最有名的例子当属“啤酒与纸尿布”的故事了,实际就是 做了A,然后又会去做B 。

一个直接的应用就是购物篮分析,或者更流行的,推荐系统( recommendation system )。这些都是能很快想到的应用。可能用到的场所比如沃尔玛(也是之前的啤酒尿布的故事来源)、豆瓣儿(我猜,我猜,我猜猜猜)、AmazonTaobao或者NetFlix之类的。

提到关联规则几乎第一个跳出来的要讲的就是Apriori系列的算法,此算法是前IBM Lab的Rakesh Agrawal大牛在94的VLDB的一篇叫《Fast Algorithms for Mining Association Rules》的paper里提出来的,该算法在2006年的ICDM里被评选为Top 10 algorithms in data mining. 这个paper也有超过8k的引用,可谓是非常非常的seminal了。

这儿有个八卦,2006年的时候微软偷偷挖走了Rakesh,IBM一看急了,你这个把我们数据组核心专家挖走了以后日子还怎么过啊!而且IBM之前也是给了有超过70万美金的股票期权等来试图以这种方式留人,结果二月份时候Rakesh先是把期权给卖了,然后才加入了M$。IBM就直接一纸诉状给他告上了法庭。结果不了了之,搞技术的挖墙角的事儿见多了。

回到正题,Apriori要解决的是:找出出现的次数大于一个指定的threshold的项集(itemSet)。直接暴力解决的复杂性是不言而喻的,单一个n元素的集合的不同的子集的个数就有{2^n}个,就别说再搭配了。而Apriori的算法的核心思想就是化大为小,从item很小开始做起,慢慢变大。

“老鼠的爸爸也是老鼠”原理:非频繁项集的超集也是非频繁的
if an itemset is not frequent, any of its superset is never frequent

很容易理解吧,因为超集的support(支撑度def: Freq/Obs)肯定小于等于子集嘛。理解了这么多基本就可以猜出算法啦:

image

第三行的函数Apriori-gen函数分两步走:

  1.  
    1. 连接步: R_{k+1},连接所有的满足前{k-1}个元素相同的P_k和R_k生成一个k+1元的itemset
      e.g.:P_k={ a_1, a_2, …a_{k-1}, a_k},  R_k={ a_1, a_2, …a_{k-1}, a_k’ }
            —> R_{ k+1 }={ a_1, .. a_{k-1}, a_k, a_k’ }
    2. 剪枝步: 如果R_{k+1}中有任一k元子集R’不是频繁集,那么直接剪去该枝,如前所言,必须要是所有的自己都是频繁的,那么超集本身才可能是频繁的。

与此同时,Apriori的缺点也是一堆啦,频繁的扫描数据库,必然带来算法效率的低下,下篇给一个算法Demo和潜在的改进。

Tags: ,,.
March 14, 2009

最近一段时间非常慵懒,加上连日阴雨。除了窝在宿舍看看闲书,偶尔出去打打球之外基本没有什么活动,实在是浪费韶华。

今天出门一瞥,竟然花开燕语春欣然而至也!遂决定从连日冬眠里复苏,重出江湖。

先弄个昨日的题目:

Subset SUM Problem
{a[1],a[2]…a[k]} choose some a[i]s
S.T.
\sum a[i]=T   T is a positive integer.

其实就是个简单的0-1背包问题
可以用DP来解:

f(i,x)=Max{  f(i-1,x-a[i])+a[i]   f(i-1,x) }

这个是背包的变种。。i.e.  重量w[i]和价值c[i]是一样的。
采取非递归算法(只需要从f(1,x)开始往上推就好了),复杂度 O(KT)

那如果这个背包的解是f(k,T)=T那么问题就解决了。

—————–

不了解0-1背包的同志,可以看看这个Zero One Knapsack Problem

Tags: ,,.
December 16, 2008

部分和序列,往往是我们关注的一种东西,例如下面的题目:

问题描述:给定一个含有 n 个元素的数列,元素有正有负,找出和最小的一组相邻的数。即给定 a[n],求 i,j 使得 a[i] + a[i+1] + …+ a[j] 的和最小。

转化为和序列:S[1],S[2]…S[n],求$latex Min: S_{[j]}-S_{[i]}$,具体的可以参考Solrex的文章,这个问题给我们的愉悦主要体现在后来的min max 的转换上。
下面我想再举一个例子来说明如何做这类部分和序列问题

Problem Description:
一个拳击手在75天的赛季里,每天都要最少打一场比赛,但是整个赛季不能打超过125场比
赛。那么,我们可以证明,可以从赛季中选出连续的K天,使得这K天的比赛总场数是30场。

这个是个很有趣的问题,我们可以证明,不仅仅是30,甚至是所有小于等于30的场次都可以通过上面的方法选出来。

分析:
抽象成数学问题:

$latex X_{[k]}$ $latex \in$ $latex \mathbb{N}$,$latex X_{[k]}$ $latex \geq 1 $, $latex \sum_{k=1}^{75} X_{[k]}\leq 125$

Prove: Exist $latex i,j$ ($latex j \geq i$),S.T. $latex \sum_{k=i}^j X_{[k]} =30$

首先,这是个部分和序列的问题,如果要用累加这种相对朴素的方法直接求解部分和序列的问题会使问题变得复杂化。那么转化为和序列是个好主意。
令$latex S_{[i]}= \sum_{k=1}^i X_{[k]}$,那么就是要证明存在$latex i,j$,使得$latex S_{[j]}-S_{[i]}=30$;

下面就是这个题目精彩的地方了:构造抽屉,{1,31},{2,32},…{61,91}{62,92}..{90,120}{121}{122}{123}{124}{125},每个{}内为一个抽屉,共有65个抽屉,要从中选出75个数,必然有一个抽屉内的两个数被选出来了,哈,这不是最朴素的那种抽屉原理么。
所以问题得以解决。

反过来思考这个问题,还是有那么点意思的:-)
1. 部分和序列转化为和序列的差。
2. 巧妙的构造抽屉

下期预告:
马尔可夫过程的首达及其应用:-)

Tags: ,.
April 23, 2008

其实无论是你这里的+N还是taocp里面求逆序中的改用相反数,本质都相同,都是使用了数据中一些没有被使用的bit位。
而对于这道题目,在n <2^31时,如果可以这样做,还有更加简单的方法。
直接将原数组的最高比特位看作一个比特位数组就可以了

C/C++ code

bool duplicate=false;
for(i=0;i<N;i++){
   int x=abs(a[i]);
   if(a[x-1]<0){
      duplicate=true;
      break;
   }else{
      a[x-1]=-a[x-1];
   }
}
for(i=0;i<N;i++){
    a[i]=abs(a[i]);
}
return duplicate;


]]>

Abstract Given two strings S of length m and string T of length n, the paper presents a new algorithm for calculating the similarity of the two strings. By the LCSubstr (longest common substring) algorithm we can find the maximal matching of the two given strings. Then eliminate the LCSubstr we will get two temp result strings. My algorithm will calculate the temp result strings iteratively until the two result strings’ common string is null. The similarity of the two strings will be measured by accumulating the non-linear mapping length of the maximal matched substring. The algorithm is always searching for the maximal continuous matching (MCM) in every step. In the end of the article I will introduce an application of this algorithm.

Keywords: pattern matching, LCSubstr, non-linear mapping, string similarity, maximal continuous matching (MCM)

April 22, 2008

Toy程序中很重要的一个功能是去重:即去掉那种转载流的文字,转载扩赛了信息但是也造成了相当麻烦的信息冗余,我不想看的信息逼着我看了一遍又一遍。
最牛逼的方法当然是能比较两个文章的全文,看全文的匹配度了,但是这个方法的时间代价太大。还有那种选取一部分Digest 出来比较的方法理论性远远大于使用性。最直接的方法就是看两个文章的标题的最长公共子串,亦即LCS( longest common substring).

LCS的原理非常的简单:

A串为:   A1 A2 A3 …..  An
B串为: B1 B2 B3 …..  Bm

只要反复的算下AB以各种位置叠在一起的最长连续字符个数就好了

数学上来说:就是写成这样一个矩阵:
match[n][m]=

  A1 A2 ….. ….. Am
B1 01 01 01
B2 01 01 01
Bn 01 01 01

中间的值match[i][j]都是0或者1 (match[i][j]=1 means Bi=Aj),下面就在这个表中选出最长的连续对角线都是1的串,对应的子串就是AB的最大的匹配。

举个例子吧:

from:  http://www.5do8.com/blog/doc/569/index.aspx

  A= I MISS MY CODE HI

  B= One Like MY Code

  i m i s s m y c o d e h i
o 0 0 0 0 0 0 0 0 1 0 0 0 0
n 0 0 0 0 0 0 0 0 0 0 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0
l 0 0 0 0 0 0 0 0 0 0 0 0 0
i 1 0 1 0 0 0 0 0 0 0 0 0 1
k 0 0 0 0 0 0 0 0 0 0 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0
m 0 1 0 0 0 1 0 0 0 0 0 0 0
y 0 0 0 0 0 0 1 0 0 0 0 0 0
c 0 0 0 0 0 0 0 1 0 0 0 0 0
o 0 0 0 0 0 0 0 0 1 0 0 0 0
d 0 0 0 0 0 0 0 0 0 1 0 0 0
e 0 0 0 0 0 0 0 0 0 0 1 0 0

那个mycode就是最长匹配的串
在具体计算的时候考虑到汉字字符的多变性和英文很不一样,我们可以直接计算一个对角线上的所有的1而不用考虑联系性。
就变成了MCC(Max common characters)了,而这个MCC就是我们去判定重复的一个重要依据。
如果len(MCC) / min( len(string_A) ,len(string_B))>valve_Value就判定为转载。
———————–
这里可以有一个非常重要的改进,认为连续匹配会有非线性加成,如match_degree=sigma( len(common_substring[i])^2)
甚至我觉得可能某些搜索引擎就是这么干的。。【未验证】

———————-
这样就实现了新闻的唯一性的保证,为了确保系统的效率不会被这个比较拖累的太多,可以只比较最近3个月的标题。

晚上写一个实现,能配合现在已经有的模块实现标题的唯一性。

听从Solrex的建议,在学习的时候直接看Python的tutorial和Lib,然后通过写一些简单的代码来逐步熟悉库:)
Mock Bank的测试工作已经进行的差不多了,最近要集中精力来做这个“可配置的Spider”

这个玩意的需求是具有普遍性的,我们有时候会去搜索引擎反复的搜索某个关键字,比如特别关注奥运的 可能每天都去搜索下和奥运有关的新闻。但是这么做的人倒没有想象的多,就是因为搜索引擎的重复结果太令人烦躁了。这个东西很讨厌,我举个例子就很清楚了:

单击显示大图
Google

当然这个是冗余中的一种:由于转载引起的搜索结果冗余
另外一种我管他叫挖坟,什么叫挖坟:历史沉淀引起的结果冗余。
Google下 奥运火炬就可以了。很多奥运火炬手选拔的网页由于SEO的作用很靠前,那么我最想看的敏感事件呢,基本是没有的。

现在Google news已经做得很好了,但是出于学习的态度和扩展性的态度。还是试探性的写写吧:)
——————————————-

April 12, 2008