LeetCode之實現IndexOf()
目錄:
聲明
博客中關於算法截圖,來自七月算法PPT,bilibili地址
博文涉及代碼地址:碼雲
原題
解題思路
暴力法
public int strStr(String haystack, String needle) {
if (needle.length() == 0) {
return 0;
}
int needStart = 0;
//for 循環每個位置開始匹配
for (int i = 0; i + needStart < haystack.length(); i++) {
//從首位開始比較
while (i + needStart < haystack.length() && needStart < needle.length()) {
if (haystack.charAt(i + needStart) == needle.charAt(needStart)) {
//匹配,則比較位置向後一位
needStart++;
} else {
//不匹配,比較位置歸零,跳出循環,i向後移動一位
needStart = 0;
break;
}
}
//如果比較位置超過了,匹配字符長度,則是已經匹配到
if (needStart >= needle.length()) {
return i;
}
}
//沒有匹配到返回-1
return -1;
}
KMP算法
算法說明
- kmb算法解釋
- kmb核心算法 next()
看完想法:next()函數作用,就是求前綴和後綴是否重複部分,有重複的時候,在平移的時候要考慮
算法實現
/**
* @param haystack 源字符串
* @param needle 匹配字符串
* @return int
* @throws
* @author Eric
* @date 2019/5/22
**/
public int kmpStrStr(String haystack, String needle) {
if (needle.length() == 0) {
return 0;
}
int[] next=next(needle);
int p=0;
int i=0;
while(i<haystack.length()){
if(p == -1||haystack.charAt(i)==needle.charAt(p)){
++p;
++i;
}else{
p=next[p];
}
if(p>=needle.length()){
return i-p;
}
}
return -1;
}
/**
* <p>
* 求出 匹配字符串得next函數
* 0 j=0
* next()= Max{k|0<k<j , P1 P2 ...Pk=Pj-k+1 Pj-k+2}
* 1 其他情況
* </p>
*
* @param needle 1
* @return int[]
* @throws
* @author Eric
* @date 2019/5/22
**/
public int[] next(String needle) {
int[] arr = new int[needle.length()+1];
arr[0]=-1;
for (int i = 0; i < needle.length(); i++) {
int k=i;
if ( i== 0) {
arr[i+1] = 0;
} else if (0 < k && k <= i) {
while (k > 0) {
if (needle.substring(0, k).equals(needle.substring(i+1 - k , i+1))) {
arr[i+1] = k;
break;
}
k--;
}
}
}
return arr;
}
總結: 結果並不是太理想,我都不好意思貼leetcode運行結果了,消耗的空間和時間都非常的多,空間消耗比較多,主要再subString()方法會重複new對象,這裏可以優化,但是就算我優化了,也是需要遍歷,時間複雜度又提升
疑問:KMP真的有那麼優秀,再我看來,KMP真的不如BF算法,假設沒有不考慮求next數組的時間複雜度,KMP確實M+N的複雜度,但是求next數組應該是M*M(非專業,大概計算,不會推到)級別的
最後求大佬指點,哪裏不對,哪裏還有可以優化
自己優化next函數
- 不使用substring方法,自己寫方法實現同樣的效果,結果空間複雜度確實降下來了,時間複雜度依舊沒降下來,測試差不多
/**
* <p>
* 優化後的 求next數組 方法
* </p>
*
* @param needle 1
* @return int[]
* @throws
* @author Eric
* @date 2019/5/23
**/
public int[] smartNext(String needle) {
int[] arr = new int[needle.length() + 1];
arr[0] = -1;
for (int i = 0; i < needle.length(); i++) {
if (i == 0) {
arr[i + 1] = 0;
} else {
arr[i + 1] = getK(needle, i);
}
}
return arr;
}
/**
* <p>
* 求next 函數 最大k值
* </p>
* @author Eric
* @date 2019/5/23
* @param needle 字符串
* @param i 字符串 偏移位置
* @return int
* @throws
**/
private int getK(String needle, int i) {
for(int k=i;k>0;k--){
for(int j=1;j<=k;j++){
if(needle.charAt(k-j)!=needle.charAt(i+1-j)){
break;
}
if(j==k){
return k;
}
}
}
return 0;
}
百度到next優化
/**
* <p>
* 百度到最優 next 求解
* </p>
* @author Eric
* @date 2019/5/23
* @param needle 字符串
* @return int[]
* @throws
**/
public int [] fastNext(String needle){
int len = needle.length();
int [] next=new int[len+1];
next[0]=-1;
if(needle.length()==0){
return next;
}
//初始化
next[1]=0;
for(int i=1,k=0;i<len;i++) {
//這個while是最關鍵的部分
while(k>0 && needle.charAt(k)!=needle.charAt(i)){
k=next[k];
}
//等價於 k=next[next[i-1]-1]
//等號右邊的k起的只是下標的作用
if(needle.charAt(k)==needle.charAt(i)){
//相等就+1
k++;
}
//賦值
next[i+1]=k;
}
return next;
}
三種next 時間測試結果
- 這裏就多解釋,百度的到時候複雜度是O(N) 級別的
BF算法
算法說明
感受: 個人覺得BF算法比KMP算法好理解多了,KMP最難理解就是next函數
算法實現
/**
* <p>
* BF 算法實現的 indexOf() 方法
* 壞字符串概率
* 移動量=匹配字符串出現壞樹的時候 匹配字符串的下標-源字符串(壞字符串)在被匹配字符串再次出現的下表
* A A A A A A becsdsddadadsd A 壞字符串
* |
* b A b d d a
* 偏移量=5-1 4
* </p>
* @author Eric
* @date 2019/5/22
* @param hayStack 源字符串
* @param needle 匹配字符串
* @return int 匹配的初始位置
* @throws
**/
public int bfIndexOf(String hayStack, String needle) {
if (needle.length() == 0) {
return 0;
}
//初始化長度
int hLen=hayStack.length()-1;
//初始化長度
int nLen=needle.length()-1;
//i 源字符串 偏移量
int i=nLen;
// 匹配字符串偏移量
int index=nLen;
while(i<=hLen){
// 源字符串向後匹配 偏移量
int yd=i;
while(index>=0){
if(hayStack.charAt(yd)==needle.charAt(index)){
//匹配成功 則向後匹配
yd-- ;
index--;
if(index<0){
return i-nLen;
}
}else{
//匹配失敗則是壞字符串,匹配壞字符串是否有匹配的
int match=-1;
for(int j=index-1;j>=0;j--){
if(hayStack.charAt(yd)==needle.charAt(j)){
match=j;
break;
}
}
i+=index-match;
index=nLen;
break;
}
}
}
return index<0?i-nLen:-1;
}