LeetCode-Algorithms #005 Longest Palindromic Substring, Database #179 Consecutive Numbers
LeetCode-Algorithms #005 Longest Palindromic Substring
英語學習時間
palindromic: [醫] 復發的, 再發的
在數學和計算機上,就指回文
這道題目就是找出給定字符串中最長的回文子串, 可以假定原字符串的長度不超過1000
直接遍歷來做肯定是不難, 但也可以想見一定是慢得可以.
那麽我的另一個想法是, 從原串中的每一個字符, 或每兩個字符中間的空隙開始, 向左右兩邊判斷是否為回文串, 最後找出最長的
1 class Solution { 2 public String longestPalindrome(String s) {3 //首先排除特殊情況 4 if (s == null || "".equals(s) || s.length() == 1) { 5 return s; 6 } else { 7 //先建立一個空串以儲存結果 8 String result = ""; 9 //獲取原字符串的長度 10 int len = s.length(); 11 12 //因為之前已經排除了特殊情況, 所以到這裏原串的長度至少為2, 那麽為了找到最長的回文子串, 我們只需要遍歷到倒數第二個字符即可13 for (int i = 0; i < len - 1; i++) { 14 //首先考慮以第i個字符為中心, 向兩側做判斷的情況 15 int begin = i, end = i; 16 while (true) { 17 //如果begin或end的外側未達到邊界則繼續判斷 18 if (begin > 0 && end < len - 1) { 19 //如果begin左側的字符和end右側的字符相同則向兩側延伸一位 20 if (s.charAt(begin - 1) == s.charAt(end + 1)) { 21 begin--; 22 end++; 23 } else { //反之則結束循環 24 break; 25 } 26 } else { //如果begin或end已達到邊界則終止循環 27 break; 28 } 29 } 30 //判斷最後取得的回文子串是否比之前存儲的結果長 31 if (result.length() < (end - begin + 1)) { 32 //如果是則替換結果 33 result = s.substring(begin, end + 1); 34 } 35 36 //再以i和i+1之間的空隙為中心向兩側進行判斷 37 begin = i; 38 end = i + 1; 39 //如果i處的字符和i+1處不同則直接跳過, 反之則繼續進行判斷 40 if (s.charAt(begin) == s.charAt(end)) { 41 //後面內容同上半部分 42 while (true) { 43 if (begin > 0 && end < len - 1) { 44 if (s.charAt(begin - 1) == s.charAt(end + 1)) { 45 begin--; 46 end++; 47 } else { 48 break; 49 } 50 } else { 51 break; 52 } 53 } 54 if (result.length() < (end - begin + 1)) { 55 result = s.substring(begin, end + 1); 56 } 57 } 58 } 59 //最後返回結果 60 return result; 61 } 62 } 63 }
順利通過, 但是成績很一般, 作為一道經典題目, 強者們的速度可以說相當喪心病狂了,
這裏面涉及到一個經典算法--Manacher‘s Algorithm, 也就是傳說中的馬拉車算法, 今天研究了一下, 可以稍微談一談,
我上面的這種寫法, 時間復雜度是O(n2), 沒有進行任何的優化, 如果跳過一些不必要的計算, 應該還可以快上不少, 但馬拉車可以做到O(n)的時間復雜度, 相當高端了
具體實現的思路是這樣的:
在我上面的寫法中, 從字符串的第一個字符開始進行遍歷時, 每次檢驗都要分兩種情況:
1) 以該字符為中心向兩側檢驗
2) 以該字符與該字符的下一個字符間的空隙為中心向兩側檢驗
而在馬拉車算法中, 會首先向字符串的各個字符間插入一個特殊字符(多用#)
這樣 babad 就會變成 #b#a#b#a#d#, aa 就會變成 #a#a#, 這樣就避免了分類討論的情形.
之後, 我們建立一個與新字符串長度相同的整數數組, 每個位置存儲以該位置為中心的回文子串的長度,如:
#b#a#b#a#d#
13171713131
為了方便計算, 我們再將這個結果長度都除以二:
#b#a#b#a#d#
01030301010
如果有了這個數組, 那麽最長的回文子串顯然也就找到了, 我們的目標就是計算出這個數組, 讓我們看一下馬拉車的思路
#a#b#a#b#a#b#a#b#a#c#d#e#
如對上面這個數組進行遍歷,
第一位#對應的顯然是0, 第二位a對應的是1, 第三位#是0, 第四位b是3,第五位#是0,第六位a是5,第7位#是0,
對第8位的b進行判斷時, 由於以第6位a為中心的回文子串會向左右各覆蓋5位, 那麽顯然第8位的b在這個範圍之內.
那麽, 以第8位b為中心的回文子串最少應該與以第四位b為中心的回文子串等長, 也就是左右各覆蓋三位,
因此我們可以從第8位b的左右各第四位開始測試, 這樣就節約了計算量, 最後得到第8位b對應的數值是7.
按照這個思路, 我們可以在遍歷中設定一個最右邊界, 在對特定字符進行檢驗是, 如果該字符在已知的回文子串覆蓋下,
那麽就計算其相對最右邊界回文串中心對稱的位置, 得出已知回文串的長度.
判斷該長度和右邊界,如果達到了右邊界,那麽需要進行中心擴展探索。
當然,如果第3步該字符沒有在最右邊界的“羽翼”下,則直接進行中心擴展探索。進行中心擴展探索的時候,同時又更新右邊界.
上面的敘述部分參考(抄襲)了下面這篇文章.
【面試現場】如何找到字符串中的最長回文子串?
這裏貼一個寫得很漂亮的答案, 雖然用的是馬拉車的思路, 但並不完全按照上面的步驟實現
1 public class Solution { 2 3 int len = 0, maxLength = 0, init = 0; 4 5 public String longestPalindrome(String s) { 6 7 char[] chars = s.toCharArray(); 8 9 len = s.length(); 10 11 if (len <= 1) return s; 12 13 for (int i = 0; i < len; i++) { 14 i = manacher(chars, i); 15 } 16 return s.substring(init, init + maxLength); 17 } 18 19 public int manacher(char[] chars, int k) { 20 21 int i = k - 1, j = k; 22 while (j < len - 1 && chars[j] == chars[j + 1]) j++; 23 int nextCenter = j++; 24 25 while (i >= 0 && j < len && chars[i] == chars[j]) { 26 i--; 27 j++; 28 } 29 30 if (j - i - 1 > maxLength) { 31 maxLength = j - i - 1; 32 init = i + 1; 33 } 34 35 return nextCenter; 36 } 37 38 }
LeetCode-Database #179 Consecutive Numbers
找出所有連續出現過至少三次的數字
1 SELECT DISTINCT 2 l1.Num AS ConsecutiveNums 3 FROM 4 Logs l1, 5 Logs l2, 6 Logs l3 7 WHERE 8 l1.Id = l2.Id - 1 9 AND l2.Id = l3.Id - 1 10 AND l1.Num = l2.Num 11 AND l2.Num = l3.Num 12 ;
答案長這樣, 也沒什麽好說的了
再貼一個好一點的答案
1 # Write your MySQL query statement below 2 # select a.Num as ConsecutiveNums from Logs a inner join 3 # (select b.Id, b.Num from Logs b inner join Logs c 4 # on b.Id=c.Id-1 and b.Num=c.Num) d 5 # on a.Id=d.Id-1 and a.Num=d.Num 6 # Group by a.Num 7 8 SELECT DISTINCT(Num) AS ConsecutiveNums 9 FROM ( 10 SELECT 11 Num, 12 @counter := IF(@prev = Num, @counter + 1, 1) AS how_many_cnt_in_a_row, 13 @prev := Num 14 FROM Logs y, (SELECT @counter:=1, @prev:=NULL) vars 15 ) sq 16 WHERE how_many_cnt_in_a_row >= 3
LeetCode-Algorithms #005 Longest Palindromic Substring, Database #179 Consecutive Numbers