leetcode打卡12 題號5 最長回文子串

2021-10-04 20:48:25 字數 3785 閱讀 3243

給定乙個字串 s,找到 s 中最長的回文子串。你可以假設 s 的最大長度為 1000。

示例 1:

輸入: 「babad」

輸出: 「bab」

注意: 「aba」 也是乙個有效答案。

示例 2:

輸入: 「cbbd」

輸出: 「bb」

暴力解法其實很簡單,就是不停的去抽取子串,然後判斷是否為回文串即可.

但是這裡我們的方法在提交的時候會顯示超出時間限制,因為這個時間複雜度是o(n3)

public string longestpalindrome

(string s)}}

return resultstr;

}public boolean isvalite

(string str)

return

true

;}

常見錯誤:

有些人會忍不住提出乙個快速的解決方案,不幸的是,這個解決方案有缺陷(但是可以很容易地糾正):

反轉 s,使之變成 s』 ,找到 s 和 s』之間最長的公共子串,這也必然是最長的回文子串。

這似乎是可行的,讓我們看看下面的一些例子。

例如,s = 「caba」, s』 =「abac」

s 以及 s』之間的最長公共子串為「aba」,恰恰是答案。

讓我們嘗試一下這個例子:s = 「abacdfgdcaba」, s』=「abacdgfdcaba」:

s 以及 s』之間的最長公共子串為「abacd」。顯然,這不是回文。

演算法設計:

1.我們可以看到,當 ss 的其他部分中存在非回文子串的反向副本時,最長公共子串法就會失敗。為了糾正這一點,每當我們找到最長的公共子串的候選項時,都需要檢查子串的索引是否與反向子串的原始索引相同。如果相同,那麼我們嘗試更新目前為止找到的最長回文子串;如果不是,我們就跳過這個候選項並繼續尋找下乙個候選。

2.對於最長公共子串,我這裡專門寫了一篇部落格講解動態規劃實現最長公共子串行和最長公共子串

中心思想:

1.例如在「xaay」中,我們找到了乙個回文串為「aa」的時候,我們只需要判斷 x ==y 就可以判斷「xaay」是否為乙個回文串

2.例如我們在「xabay」,我們找到了「aba」為回文串的之後,還是要判斷x == y,然後就可以進行判斷了

3.所以我們這裡的核心思想就算是尋找到一位的回文,兩位的回文,三位的回文,然後去找更長的回文

演算法設計:

1.如何理解中心擴散,其實就是每次定位乙個座標,然後從這個字元開始向兩邊同時擴散尋找最長的回文串,擴散分為三步

2.例如:s = 「abcccbs」 (假設已經定位到了s = c)

3.此時i = 3,left = i - 1,right = i + 1 ,left代表當前定位字元左邊的字元,right代表當前定位字元右邊的字元

4.一路向左遍歷,此時s【left】 = s【i】 = c,那就意味著s【left…i】此時就是乙個回文串,之後left - 1,繼續看左邊是否相等,直到不等位置,在這次的遍歷結束後,我們會找到s【left+1…i】,這個子串是乙個回文串,並且這個回文串一定是所有字元都相同的(本次遍歷結束後找出的是cc)。此時left = 2 ,s【left】= b

5.再一路向右遍歷,和上面一樣,此時s【right】 = s【i】 = c,那就意味著此時s【i…right】是乙個回文串,之後right+ 1,繼續看右邊是否相等,直到不等位置,本次結束後我們就可以找到 s【left + 1…right - 1】是乙個回文串,並且所有字元相等(本次遍歷結束後找出的是ccc)。right = 6 ,s【right】 = b

6.之後我們同時向左右遍歷,因為此時s【left+1,right-1】已經是乙個全部相同的回文了,我們此時只需要判斷s【left】== s【right】是否相等,此時由於s【left】== s【right】 = b,那就說明此時s【left…right】就是乙個回文串,然後將left - 1, right + 1,這樣最後遍歷結束後我們就可以找到 s【left+1…right- 1】是乙個以 s【i】為中心的最長回文串。同時記錄下標即可。

/**

* 中心擴散 沒有優化

* @param s

* @return

*/public

static string longestpalindrome2

(string s)

//往右邊遍歷

while

(right length()

&&(s.

charat

(right)

== s.

charat

(i))

)//同時向左向右遍歷

while

(left >=

0&& right < s.

length()

&&(s.

charat

(right)

== s.

charat

(left)))

if(len > maxresult)

}return s.

substring

(beginindex,quitindex +1)

;}

理解:

1.動態規劃其實大概的意思就是我們要保留之前小問題的計算結果,當我們計算大問題的時候會用到我們小問題的計算結果

2.這個演算法的設計思想和解法三是一樣的,只不過我們會保留之前的計算結果,舉個例子,例如我現在要判斷s【2…8】是否為回文,但是由於之前我已經判斷過s【3…7】是不是回文,所以我將先判斷s【3…7】是不是回文(這裡只需要取出之前的判斷結果即可,不需要重新計算),如果s【3…7】是回文,那麼我就判斷s == s,這樣就可以很簡單的判斷s【2…8】是否為回文

演算法設計:

1.動態規劃基本都是這樣,先定義乙個dp矩陣用來儲存計算結果,所以我也定義dp【s.length】【s.length】 = 0;

2.dp【i】【j】 = 1 代表的含義是s【i…j】是回文,等於0則代表不是回文

3.那麼我們每次判斷s【i…j】是不是回文,就得看s【i+1…j-1】是不是回文,也就是看dp【i+1】【j-1】 == 1,

4.若dp【i+1】【j-1】 = 0, 那麼dp【i】【j】 = 0,

5.若dp【i+1】【j-1】 = 1 並且 s【i】= s【j】,那麼dp【i】【j】 = 1

6.所以我們無非就是遍歷乙個dp矩陣,分別進行判斷即可。但是這裡有幾個問題需要注意:

public

static string longestpalindrome5

(string s)

else

if(i +

1> j -

1&& s.

charat

(i)== s.

charat

(j))

else

if(i +

1<= j -

1&& dp[i+1]

[j-1]==

1&& s.

charat

(i)== s.

charat

(j))

else

if(dp[i]

[j]==

1&& j-i+

1> lenresult)}}

return s.

substring

(beginindex,quitindex+1)

;}

leetcode打卡9 題號2 兩數相加

給出兩個 非空 的鍊錶用來表示兩個非負的整數。其中,它們各自的位數是按照 逆序 的方式儲存的,並且它們的每個節點只能儲存 一位 數字。如果,我們將這兩個數相加起來,則會返回乙個新的鍊錶來表示它們的和。您可以假設除了數字 0 之外,這兩個數都不會以 0 開頭。示例 輸入 2 4 3 5 6 4 輸出 ...

寒假LeetCode打卡(5)

給定乙個二叉樹,找出其最大深度。二叉樹的深度為根節點到最遠葉子節點的最長路徑上的節點數。說明 葉子節點是指沒有子節點的節點。示例 給定二叉樹 3,9,20,null,null,15,7 3 9 20 15 7 返回它的最大深度 3 題目分析 還是使用遞迴,找出左右兩邊的層數,最後加一 根節點 錯點分...

leetcode題目。題號1

題目描述 給定乙個整數陣列和乙個目標值,找出陣列中和為目標值的兩個數。你可以假設每個輸入只對應一種答案,且同樣的元素不能被重複利用。示例 給定 nums 2,7,11,15 target 9 因為 nums 0 nums 1 2 7 9 所以返回 0,1 解題思路 迴圈遍歷所有可能,每一次判斷是否與...