剑指Offer018 - 020 刷题笔记 回文 双指针DP中心扩展
Posted 牧心.
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指Offer018 - 020 刷题笔记 回文 双指针DP中心扩展相关的知识,希望对你有一定的参考价值。
文章目录
018 - 剑指 Offer II 018. 有效的回文【双指针】
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public boolean isPalindrome(String s) {
int left = 0, right = s.length() - 1;
while (left < right) {
while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
left++;
}
while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
right--;
}
if (left < right) {
if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right))) {
return false;
}
left++;
right--;
}
}
return true;
}
}
019 - 剑指 Offer II 019. 最多删除一个字符得到回文【贪心+双指针】
设两个指针从字符串两端向中心靠拢,如果左右指针指向字符相等,则继续向中心靠拢;如果不相等,则必须删除其中一个,那么就产生了两种情况:删除左边字符、或 删除右边字符,只要以上这两种情况有一个符合是回文串就返回 t r u e true true,否则返回 f a l s e false false。
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public boolean validPalindrome(String s) {
int left = 0, right = s.length() - 1;
while (left < right) {
if (s.charAt(left) == s.charAt(right)) {
left++;
right--;
} else {
return isPalindrome(s, left + 1, right) || isPalindrome(s, left, right - 1); // 删除左 || 删除右
}
}
return true;
}
// 判断字符串s是否是回文串
private boolean isPalindrome(String s, int left, int right) {
while (left < right) {
if (s.charAt(left) == s.charAt(right)) {
left++;
right--;
} else {
return false;
}
}
return true;
}
}
020 - 剑指 Offer II 020. 回文子字符串的个数【动态规划、中心扩展】
方法一:动态规划
设置 d p [ i ] [ j ] dp[i][j] dp[i][j]表示字符串 s s s在 [ i , j ] [i,j] [i,j]区间的子串是否是一个回文串。
状态转移方程:$dp[i][j] = \\left{
\\begin{aligned}
true, 如果 s[i] == s[j] 并且 (j-i<=1 || dp[i+1][j-1]) \\
fasle, 其他
\\end{aligned}
\\right.
$
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( n 2 ) O(n^2) O(n2)
class Solution {
// 动态规划
public int countSubstrings(String s) {
int n = s.length();
boolean[][] dp = new boolean[n][n];
int cnt = 0;
// 按列计算dp
for (int j = 0; j < n; j++) {
for (int i = 0; i <= j; i++) {
if (s.charAt(i) == s.charAt(j) && (j - i <= 1 || dp[i + 1][j - 1])) {
dp[i][j] = true;
cnt++;
}
}
}
return cnt;
}
}
方法二:中心扩展
对于一个子串,选择最中间的a作为中心点,往两边扩展,如果中心串是回文串,并且向两侧扩展的左右两个字符一样,则产生了一个新的回文串,依次继续扩展。
对于“中心点”,可以是一个字符,也可能是两个字符,这样中心点的个数就有 2 ∗ n − 1 2*n-1 2∗n−1个,其中单个字符的中心点有 n n n个,两个字符的中心点有 n − 1 n-1 n−1个。
- 时间复杂度: O ( n 2 ) O(n^2) O(n2)
- 空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
// 中心扩展
public int countSubstrings(String s) {
int n = s.length();
int freq = 2 * n - 1;
int cnt = 0;
for (int i = 0; i < freq; i++) {
int left = i / 2, right = i / 2 + i % 2;
while (left >= 0 && right < n && s.charAt(left) == s.charAt(right)) {
left--;
right++;
cnt++;
}
}
return cnt;
}
}
以上是关于剑指Offer018 - 020 刷题笔记 回文 双指针DP中心扩展的主要内容,如果未能解决你的问题,请参考以下文章