LeetCode-Algorithms #005 Longest Palindromic Substring, Database #179 Consecutive Numbers

Posted chang4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的主要内容,如果未能解决你的问题,请参考以下文章

leetcode-algorithms-92. Reverse Linked List II

leetcode-algorithms-109. Convert Sorted List to Binary Search Tree

LeetCode-Algorithms 1. 两数之和

LeetCode-Algorithms #007 Reverse Integer, Database #182 Duplicate Emails

LeetCode-Algorithms #001 Two Sum, Database #175 Combine Two Tables

LeetCode-Algorithms #003 Longest Substring Without Repeating Characters, Database #177 Nth Highest S