在簡單證明kmp之前,先分析一下樸素演算法以及一種模式串沒有相同字元的特殊情況下的變形,方便一步一步匯入kmp演算法的思路中。
樸素演算法
樸素演算法比較明了,不再贅述,下面是簡單的**:
// time : o(n*m), space : o(1)
int *****(const
std::string &text, const
std::string &pattern)
}if (j == len2) return i;
}return -1;
}
分析樸素演算法我們會發現,實際上對於模式串某個不匹配的位置,我們沒有充分利用不匹配時產生的資訊,或者說不匹配位置之前
的已匹配的相同字首的資訊。
模式串不含有相同字元
這種情況下,當模式串的乙個位置不匹配的時候,我們可以優化樸素演算法直接跳過前面模式串已經匹配的長度,實際上這種思路和
kmp所做的優化挺類似的,下面是**以及簡單證明:
// if pattern has different chars
// we can optimize it to o(n)
// proof:
// assume match break in index j of pattern length m
// current index i : t1 t2 t3 ..tj.. tm ... tn
// p1 p2 p3 ..pj.. pm
// tj != pj
// (pk != pt) for 1 <= k,t <= m and k != t
// (pk == tk) for 1 <= k < j
// => p1 != pk for 1 <= k < j
// => so move i to j
int special_case(const
std::string &text, const
std::string &pattern)
}if (j == len2) return i;
// notice ++i
if (j != 0)
}return -1;
}
kmp
前提假設:目標文字串t的長度為n,模式串p的長度為m,arr為所謂的next陣列,i為在模式串的第i個位置匹配失敗。
需要證明的問題:對於形如a b x1 x2… a b y1 y2… a b的模式串,為什麼可以將模式串直接移到最後乙個a b處進行下一次匹配,而不是在中間某個a b處?也就是說為什麼以中間某個 a b開頭進行匹配不可能成功。(注意這裡為了方便只有a b兩個字元,實際上可能是多個,並且中間的a b和第乙個以及最後乙個 a b使可能部分重合的)。
簡單證明
雖然不是很正規(應該很不正規…),但是還是多少能幫助理解吧:-)
最後附上kmp**
// longest common prefix and suffix of
// substr of pattern[0, i]
// use dyamic programming
// time : o(m), space : o(m)
std::vector
nextarray(const
std::string &pattern)
res[i] = res[i - 1];
}//for (auto &&ele : res)
return res;
} // time : o(n) + o(m), space : o(m)
int kmp(const
std::string &text, const
std::string &pattern)
}// got one
if (j == len2) return i;
// move to next position
// notice the ++i
// we can skip j == 0
if (j != 0)
//std::cout << "j:" << j << " i:" << i << std::endl;
}return -1;
}
洗牌演算法的隨機性簡單證明。
所謂洗牌演算法,就是產生乙個包含指定範圍的所有數的隨機序列。主流的洗牌演算法的實現如下 對於n張牌,用大小為n的陣列a n for i 0 i我們總是擔心他的隨機性是否能保證,這裡有乙個很簡單的理解。可以先達成乙個共識 如果 1.一張牌出現在任何位置的概率是相等的。2.乙個位置出現任何牌的概率是相等...
kmp優化正確性證明
鄧俊輝老師的課上給出了一種普遍的kmp演算法優化,但是沒有給出這種優化的正確性證明。或許這種正確性是顯而易見的,但這裡還是研究了一下這個演算法的正確性問題。int buildnext char p else 原演算法 j next j 優化演算法 j newnext j return next 顯然...
KMP簡單應用
kmp簡單應用 time limit 1000ms memory limit 65536k 給定兩個字串string1和string2,判斷string2是否為string1的子串。輸入包含多組資料,每組測試資料報含兩行,第一行代表string1 長度小於1000000 第二行代表string2 長...