公式證明
在之前的某一篇部落格中我寫了,關于BDKRHash的簡短的介紹,還沒有對其公式和原理進行闡述,實在是罪過罪過。
首先給出BDKRHash的公式
1.$$hashvalue[i]=(hashvalue[i-1]*seed+str[i]-'a'+1)%P$$(也可以用ASCLL碼值,但容易爆)
2.$$Hashvalue[l……r]=(hashvalue[r]-hashvlaue[l-1]*seed^{r-l+1})%P$$(注意第一個Hashvalue與hashvalue不同)
第一個公式不需要證明,這是BDKRHash的定義式,意思就是:發明BDKRHash的人就是這麼寫的。這個東西隻有用記憶的方法來掌握,如果要深究其原理,太過深奧,蒟蒻我不懂。
接下來我們針對第二個公式進行證明: Hashvalue代表的是從l到r這個區間的字串的hash值,hashvalue代表從第1個開始到第i個的hash值。下面開始證明
先看第一個公式
$$hashvalue[i]=(hashvalue[i-1]*seed+str[i]-'a'+1)%P$$
我們把每一項展開可以得到(為友善表達,接下來hashvalue簡寫為hash,str[i]-'a'+1簡寫為str[i])
$$hash[0]=0$$
$$hash[1]=str[1]%P$$
$$hash[2]=hash[1]*seed+str[2]$$
$$hash[3]=hash[2]*seed+str[3]$$
$$hash[i]=hash[i-1]*seed+str[i]$$
$$hash[n]=hash[n-1]*seed+str[n]$$
看出一些規律了嗎?如果沒有,我們再把每一項中的hash[i]*seed展開:
$$hash[2]=(str[1])*seed+str[2]$$
$$hash[3]=(str[1]*seed+str[2])*seed+str[3]$$
$$hash[4]=((str[1]*seed+str[2])*seed+str[3])*seed+str[4]$$
$$hash[i]=(((str[1]*seed+str[2])*seed+str[3])*seed······)*seed+str[i-1])+str[i]$$
再把括号全部展開:
$$hash[i]=str[1]*seed^{i-1}+str[2]*seed^{i-2}+······+str[i]*seed^{i-i=0}$$
到這裡我們已經大緻得到了BDKRHash的最終表達式,通過對這個式子進行變形,就可以得到第二個公式:
$$令l=1,則r=r-l+1$$
$$hash[l······r]=hash[1······r-l+1]=str[1]*seed^{r-l}+str[2]*seed^{r-l-1}+······+str[r-l+1]*seed$$
把1還原為l
$$hash[l······r]=str[l]*seed^{r-l}+str[l+1]*seed^{r-l-1}+······+str[r]*seed$$
寫到這裡,可能大家都已經明白了。
$$hash[1······l-1]=str[1]*seed^{l-2}+str[2]*seed^{l-3}+······+str[l-1]*seed\dashrightarrow①$$
$$hash[1······r]=str[1]*seed^{r-1}+str[2]*seed^{r-2}+······+str[r]*seed\dashrightarrow②$$
$$②-①*seed^{r-l+1}$$
得到 $$hash[1······r]=hash[1······l-1]*seed^{r-l+1}+str[l]*seed^{r-l}+str[l+1]*seed^{r-l-1}+······+str[r]*seed$$
$$hash[l······r]=str[l]*seed^{r-l}+str[l+1]*seed^{r-l-1}+······+str[r]*seed得$$
$$hash[l······r]=hash[1······r]-hash[1······l-1]*seed^{r-l+1}$$
又Hashvalue代表的是從l到r這個區間的字串的hash值,hashvalue代表從第1個開始到第i個的hash值。
$$Hashvalue[l……r]=(hashvalue[r]-hashvlaue[l-1]*seed^{r-l+1})%P$$
完結。 如果不懂,可以自己按着推一遍。
BDKRHash判斷回文字元串:
主要是通過下面這個式子判斷。
$$hash[i]=str[1]*seed^{i-1}+str[2]*seed^{i-2}+······+str[i]*seed$$
觀察之後不難發現,hash值是可以逆向來求的,即:
int seed=1;
for(int i=n;i>=1;i--)
{
hash[i]=hash[i+1]+str[i]*seed;
seed*=107;
}
是以我們隻用循環一遍就可以得到,1到i長度的字元串是不是回文字元串。
轉載于:https://www.cnblogs.com/Y-sofun/p/7576610.html