LeetCode 28:實(shí)現(xiàn)strStr() Implement strStr()

LeetCode 28:實(shí)現(xiàn)strStr() Implement strStr()

愛寫bug(ID:icodebugs)

作者:愛寫bug

實(shí)現(xiàn) strStr() 函數(shù)迹缀。

給定一個(gè) haystack 字符串和一個(gè) needle 字符串,在 haystack 字符串中找出 needle 字符串出現(xiàn)的第一個(gè)位置 (從0開始)愕难。如果不存在焰薄,則返回 -1

Implement strStr().

Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

Example 1:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n10" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Input: haystack = "hello", needle = "ll"
Output: 2</pre>

Example 2:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n12" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">Input: haystack = "aaaaa", needle = "bba"
Output: -1</pre>

Clarification:

What should we return when needle is an empty string? This is a great question to ask during an interview.

For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C's strstr() and Java's indexOf().

說明:

當(dāng) needle 是空字符串時(shí),我們應(yīng)當(dāng)返回什么值呢甘改?這是一個(gè)在面試中很好的問題。

對(duì)于本題而言灭抑,當(dāng) needle 是空字符串時(shí)我們應(yīng)當(dāng)返回 0 十艾。這與C語言的 strstr() 以及 Java的 indexOf() 定義相符。

解題思路(Java):

  • 暴力窮舉:

    復(fù)雜度:時(shí)間 O(n^2) 空間 O(1)

    字符串 a 從第一個(gè)索引開始 逐一匹配字符串 b 的第一個(gè)索引:a[i++]==b[0]腾节,如果為true忘嫉,則進(jìn)入內(nèi)循環(huán)字符串a(chǎn)從第 i+j 個(gè)字符開始與字符串b 第 j個(gè)字符匹配:a[i+j]==b[j]

代碼:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n26" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Solution {
public int strStr(String haystack, String needle) {
if(needle.equals(""))return 0;
int haystackLen=haystack.length(),needleLen=needle.length();
char firstChar=needle.charAt(0);
?
for(int i=0;i<=haystackLen-needleLen;i++){
if(haystack.charAt(i)==firstChar){
int j=1;
for(;j<needleLen;j++){
if(haystack.charAt(i+j)!=needle.charAt(j)) break;
}
if(j==needleLen) return i;
}
}
return -1;
}
}</pre>

  • KMP算法:

    復(fù)雜度:時(shí)間 O(n+m) 空間 O(M)

    下面引用一組圖片幫助理解(圖片來源:https://blog.csdn.net/v_july_v/article/details/7041827 ):

    說明: 圖片中字符串haystack為:"BBC ABCDAB ABCDABCDABDE"荤牍,模式串 needle 為:"ABCDABD"

    第一步開始匹配:

    image

    第二步匹配到第一個(gè)相同字符:

    image

    第三步兩個(gè)字符串逐一向后匹配,直到到字符 D 與 空格 字符匹配失敗庆冕,結(jié)束該輪次匹配:

    image

    第四步重新匹配参淫,但不用從第二步的下一個(gè)字符 B 開始,因?yàn)榭崭褡址芭c模式字符串前6個(gè)字符已經(jīng)匹配相同愧杯。既C字符之前的兩個(gè)字符 AB 與空格字符前兩個(gè)字符 AB 相同涎才,兩個(gè)字符串可直接從 空白 字符與 C 字符開始匹配:

    image

    可以看到圖片中一下跳過了 haystack 五個(gè)字符ABCDAB 和 needle 的兩個(gè)字符AB。優(yōu)化思路很清晰力九。

代碼:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" cid="n46" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Solution {
public int strStr(String haystack, String needle) {
if(needle.equals("")) return 0;
int[] next = new int[needle.length()];
getNext(next, needle);// 得到next數(shù)組
// i是匹配串haystack的指針耍铜,j是模式串needle的指針
int i = 0, j = 0;
while(i < haystack.length() && j < needle.length()){
// 如果j=-1,即next數(shù)組中該字符為第一位跌前,下標(biāo)+1后棕兼,重新匹配
if(j == -1 || haystack.charAt(i) == needle.charAt(j)){
// 如果匹配成功,則自增1抵乓,匹配下一個(gè)字符
i++;j++;
} else {
j = next[j];// 如果匹配失敗伴挚,則將j賦值next[j],避免匹配重復(fù)匹配
}
}
return j == needle.length() ? i - j : -1;
}
?
private void getNext(int[] next, String needle){
// k是前綴中相同部分的末尾灾炭,也是相同部分的長度
// j是后綴的末尾茎芋,即后綴相同部分的末尾
int k = -1, j = 0;
next[0] = -1;
while(j < needle.length() - 1){
// 如果k=-1,匹配失敗蜈出,重新開始計(jì)算前綴和后綴相同的長度
// 如果兩個(gè)字符相等田弥,則在上次前綴和后綴相同的長度加1,繼續(xù)下一段字符最大公共前后綴匹配
if (k == -1 || needle.charAt(j) == needle.charAt(k)){
k++;j++;
if (needle.charAt(j) != needle.charAt(k))
next[j] = k;
else
//因?yàn)椴荒艹霈F(xiàn)p[j] = p[ next[j ]]铡原,所以當(dāng)出現(xiàn)時(shí)需要繼續(xù)遞歸偷厦,k = next[k] = next[next[k]],以減少重復(fù)部分的多余匹配
next[j] = next[k];
} else {
// 否則燕刻,前綴長度縮短為next[k]
k = next[k];
}
}
}
}</pre>

總結(jié):

KMP算法優(yōu)化的方向很明了只泼,主要難點(diǎn)就在于對(duì)next數(shù)組的求法和理解,KMP算法不是本文的重點(diǎn)卵洗,如有興趣深入了解请唱,推薦一篇博文:https://blog.csdn.net/v_july_v/article/details/7041827

另外還有Sunday算法 是找到與模式字符串相同長度的源字符串 從右向左匹配,其中心思想為:

  • 如果該字符沒有在模式串中出現(xiàn)忌怎,直接從該字符向右移動(dòng)位數(shù) = 模式串長度 + 1籍滴。(因?yàn)樵醋址性撟址南嗤L度字符串不可能匹配)
  • 如果該字符在模式串中出現(xiàn)過,其移動(dòng)位數(shù) = 模式串中最右端的該字符到末尾的距離+1榴啸。

字符串haystackBBC ABC 與模式串needle ABCDABD 匹配孽惰,字符串haystack中的空格字符未在模式串needle 中出現(xiàn),則可以直接跳過空格字符后面六個(gè)字符的匹配鸥印,因?yàn)榘崭褡址南嗤L度字符串都不可能匹配成功勋功,所以可以跳過6個(gè)坦报。

Python3:

說明:上面兩種方法在所有語言都可行,只是語法不同狂鞋,所以在py3中不再復(fù)現(xiàn)片择,僅展示一些py3特有的語法投機(jī)取巧解題。

利用py3內(nèi)建函數(shù)find()直接得結(jié)果骚揍。

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n60" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Solution:
def strStr(self, haystack: str, needle: str) -> int:
return haystack.find(needle)</pre>

find() 方法描述

find() 方法檢測字符串中是否包含子字符串 str 字管,如果指定 beg(開始) 和 end(結(jié)束) 范圍,則檢查是否包含在指定范圍內(nèi)信不,如果指定范圍內(nèi)如果包含指定索引值嘲叔,返回的是索引值在字符串中的起始位置。如果不包含索引值抽活,返回-1硫戈。如果子字符串為空,返回0下硕。

語法

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="" cid="n65" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit;">str.find(str, beg=0, end=len(string))</pre>

參數(shù)
  • str -- 指定檢索的字符串
  • beg -- 開始索引丁逝,默認(rèn)為0。
  • end -- 結(jié)束索引梭姓,默認(rèn)為字符串的長度霜幼。

利用py3字符出切片特性解決:

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="python" cid="n75" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9em; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(248, 248, 248); position: relative !important; border: 1px solid rgb(231, 234, 237); border-radius: 3px; padding: 8px 4px 6px; margin-bottom: 15px; margin-top: 15px; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">class Solution:
def strStr(self, haystack: str, needle: str) -> int:
for i in range(len(haystack)-len(needle)+1):
if haystack[i:i+len(needle)]==needle:#截取切片
return i
return -1</pre>

注:算法導(dǎo)論第32章:字符串匹配有完整的一章相關(guān)討論。

愛寫bug.png

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末糊昙,一起剝皮案震驚了整個(gè)濱河市辛掠,隨后出現(xiàn)的幾起案子谢谦,更是在濱河造成了極大的恐慌释牺,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件回挽,死亡現(xiàn)場離奇詭異没咙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)千劈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門祭刚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人墙牌,你說我怎么就攤上這事涡驮。” “怎么了喜滨?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵捉捅,是天一觀的道長。 經(jīng)常有香客問我虽风,道長棒口,這世上最難降的妖魔是什么寄月? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮无牵,結(jié)果婚禮上漾肮,老公的妹妹穿的比我還像新娘。我一直安慰自己茎毁,他們只是感情好克懊,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著七蜘,像睡著了一般保檐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上崔梗,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天夜只,我揣著相機(jī)與錄音,去河邊找鬼蒜魄。 笑死扔亥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谈为。 我是一名探鬼主播旅挤,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼伞鲫!你這毒婦竟也來了粘茄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤秕脓,失蹤者是張志新(化名)和其女友劉穎柒瓣,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體吠架,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芙贫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了傍药。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片磺平。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖拐辽,靈堂內(nèi)的尸體忽然破棺而出拣挪,到底是詐尸還是另有隱情,我是刑警寧澤俱诸,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布菠劝,位于F島的核電站,受9級(jí)特大地震影響乙埃,放射性物質(zhì)發(fā)生泄漏闸英。R本人自食惡果不足惜锯岖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望甫何。 院中可真熱鬧出吹,春花似錦、人聲如沸辙喂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽巍耗。三九已至秋麸,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間炬太,已是汗流浹背灸蟆。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亲族,地道東北人炒考。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像霎迫,于是被迫代替她去往敵國和親斋枢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容