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
原文地址:https://www.cnblogs.com/chang4/p/9741125.html