005 Longest Palindromic Substring
1. 原题
Given a string S, find the longest palindromic substring in S. You may assume that the maximum length of S is 1000, and there exists one unique longest palindromic substring.
2. 释题
该题要求最长回文子串
思路一
遍历求每一个字符向两边生长的最长子串,时间复杂度O(N^2),而且要处理字符串长度是奇数偶数的问题,不可取。
思路二
leetcode测试4ms,速度比较快。
思路三
leetcode测试16ms,Manacher算法,时间复杂度为O(N)。这个算法要解决的就是一个字符串中最长的回文子串有多长。这个算法可以在O(n)的时间复杂度内既线性时间复杂度的情况下,求出以每个字符为中心的最长回文有多长。
这个算法有一个很巧妙的地方,它把奇数的回文串和偶数的回文串统一起来考虑了。这一点一直是在做回文串问题中时比较烦的地方。这个算法还有一个很好的地方就是充分利用了字符匹配的特殊性,避免了大量不必要的重复匹配。
算法大致过程是这样。先在每两个相邻字符中间插入一个分隔符,当然这个分隔符要在原串中没有出现过。一般可以用‘#’分隔。这样就非常巧妙的将奇数长度回文串与偶数长度回文串统一起来考虑了(见下面的一个例子,回文串长度全为奇数了),然后用一个辅助数组P记录以每个字符为中心的最长回文串的信息。P[id]记录的是以字符str[id]为中心的最长回文串,当以str[id]为第一个字符,这个最长回文串向右延伸了P[id]个字符。
原串: w aa bwsw f d
新串: # w # a # a # b # w # s # w # f # d #
辅助数组P: 1 2 1 2 3 2 1 2 1 2 1 4 1 2 1 2 1 2 1
这里有一个很好的性质,P[id]-1就是该回文子串在原串中的长度(包括‘#’)。如果这里不是特别清楚,可以自己拿出纸来画一画,自己体会体会。当然这里可能每个人写法不尽相同,不过我想大致思路应该是一样的吧。
好,我们继续。现在的关键问题就在于怎么在O(n)时间复杂度内求出P数组了。只要把这个P数组求出来,最长回文子串就可以直接扫一遍得出来了。
由于这个算法是线性从前往后扫的。那么当我们准备求P[i]的时候,i以前的P[j]我们是已经得到了的。我们用mx记在i之前的回文串中,延伸至最右端的位置。同时用id这个变量记下取得这个最优mx时的id值。
3. 答案
思路二代码
class Solution {
public:
string longestPalindrome(string s)
{
if(s.size() <= 1)
return s;
int length = s.size();
int left, right;
int maxLeft = 0;
int maxLen = 1;
int start = 0;
for(; length - start > maxLen / 2;)
{
left = right = start;
while(right < length - 1 && s[right] == s[right + 1])
{
right ++;
}
start = right + 1;
while(left > 0 && right < length - 1 && s[left - 1] == s[right + 1])
{
right ++;
left --;
}
if(maxLen < right - left + 1)
{
maxLeft = left;
maxLen = right - left + 1;
}
}
return s.substr(maxLeft, maxLen);
}
};
思路三代码
class Solution {
public:
string longestPalindrome(string s)
{
string T;// Transform S to T
for(int i = 0; i < s.size(); i ++)
T += "#" + s.substr(i, 1);
T.push_back('#');
vector<int> P(T.size(),0); // Array to record longest palindrome
int center = 0, boundary = 0, maxLen = 0, resCenter = 0;
for(int i = 1; i < T.size() - 1; i ++)
{
int iMirror = 2 * center - i; // calc mirror i = center-(i-center)
P[i] = (boundary > i) ? min(boundary - i , P[iMirror]) : 0; // shortcut
while(i - 1 - P[i] >= 0 && i + 1 + P[i] <= T.size() - 1 && T[i + 1 + P[i]] == T[i - 1 - P[i]]) // Attempt to expand palindrome centered at i
P[i] ++;
if(i + P[i] > boundary)
{ // update center and boundary
center = i;
boundary = i + P[i];
}
if(P[i] > maxLen)
{ // update result
maxLen = P[i];
resCenter = i;
}
}
return s.substr((resCenter - maxLen) / 2, maxLen);
}
};
006 ZigZag Conversion
1. 原题
The string “PAYPALISHIRING” is written in a zigzag pattern on a given number of rows like this: (you may want to display this pattern in a fixed font for better legibility)
P A H N
A P L S I I G
Y I R
And then read line by line: “PAHNAPLSIIGYIR”
Write the code that will take a string and make this conversion given a number of rows:
string convert(string text, int nRows);
convert(“PAYPALISHIRING”, 3) should return “PAHNAPLSIIGYIR”.
2. 释题
该题考察对数组行列控制的掌握情况。
思路一
初始化string[nRows]存放每行的字母,最后再连接起来,先填完整行,再填不完整行,计算较复杂,容易出错。
思路二
思路一的优化版本,详情见代码注释。
3. 答案
思路二代码
class Solution {
public:
string convert(string s, int numRows)
{
string result = "";
// simple cases that could be inferred easily
if (s.size() <= numRows || numRows == 1) return s;
// colIndex represents the "straight column" index (PAY or ALI in the example)
int colIndex = 0;
// append result row by row
for (int i = 0; i < numRows; i++)
{
// for each row, the first character is in the ith position of s;
result += s[i];
// 2*numRows - 2 is the increment amount between two straight columns
// i is the current location in this column
// so colIndex is now the position of character of the same position in the next "straight column"
colIndex = i + 2*numRows - 2;
// 2*numRows - 2 - i is the position of the character in the "tilted column" (P or S or I in the example)
// use colIndex - 2 * i (same value) because we need to increment this value every time
// while there is still character in the "tilted column":
while (colIndex - 2 * i < s.size())
{
// if it is the first or the last row, tilted column overlaps the straight column, ignore!
if (i != 0 && i != numRows - 1)
{
// first: append the character in the tilted column
result += s[colIndex - 2 * i];
}
// second: append the character in the straight column in the same row only if this position exists
if (colIndex < s.size())
{
result += s[colIndex];
}
// increment colIndex to the next column
colIndex += 2*numRows - 2;
}
}
return result;
}
};
007 Reverse Integer
1. 原题
Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321
2. 释题
该题比较简单,需要处理好整形边界和正负号问题。
3. 答案
class Solution {
public:
int reverse(int x) {
if(x == 0 || x == -2147483648)
return 0;
int unsignedx = (int)abs(x);
int minusFlag = x / unsignedx;
long long res = 0;
while(unsignedx)
{
res = res * 10 + unsignedx % 10;
unsignedx /= 10;
}
return res > INT_MAX ? 0 : (int)res * minusFlag;
}
};
008 String to Integer (atoi)
1. 原题
mplement atoi to convert a string to an integer.
Hint: Carefully consider all possible input cases. If you want a challenge, please do not see below and ask yourself what are the possible input cases.
Notes: It is intended for this problem to be specified vaguely (ie, no given input specs). You are responsible to gather all the input requirements up front.
2. 释题
该题要求实现atoi函数,需要考虑到一下几种情况的输入:
a. 含有不是0-9字符的输入
b. 正负号的检验
c. 对正负号计数,大于一个就返回0
d. 超过整型的最大最小边界
3. 答案
class Solution {
public:
int myAtoi(string str)
{
if(str.size() == 0)
return 0;
long long res = 0;
int flag = 1;
int posi = 0;
int nonNumerical = 0;
bool isNum = false;
for(int i = 0; i < str.size(); i ++)
{
if(str[i] == ' ')
{
if(isNum == true)
break;
}
if((str[i] < '0' || str[i] > '9') && str[i] != ' ' && str[i] != '+' && str[i] != '-')
{
break;
}
if(str[i] == '+' || str[i] == '-')
{
isNum = true;
nonNumerical ++;
}
if(str[i] == '-')
{
flag = -1;
}
if(str[i] >= '0' && str[i] <= '9')
{
isNum = true;
res = res * 10 + (str[i] - '0');
}
if(nonNumerical > 1)
return 0;
if(res >= INT_MAX && flag == 1)
return INT_MAX;
if(res > INT_MAX && flag == -1)
return INT_MIN;
}
res *= flag;
return res;
}
};
009 Palindrome Number
1. 原题
Determine whether an integer is a palindrome. Do this without extra space.
2. 释题
该题要求检验一个数是不是回文数,最简单的思路是将该数字高低位互换。
3. 答案
class Solution {
public:
bool isPalindrome(int x)
{
if(x < 0)
return false;
int ret = 0, t = x;
while(t) // 将高低位互换
{
ret = ret * 10 + t % 10;
t = t / 10;
};
return ret == x;
}
};