1. 题目
给你一个字符串 s ,返回 s 中 长度为 3 的不同回文子序列 的个数。
即便存在多种方法来构建相同的子序列,但相同的子序列只计数一次。
回文 是正着读和反着读一样的字符串。
子序列 是由原字符串删除其中部分字符(也可以不删除)且不改变剩余字符之间相对顺序形成的一个新字符串。
例如,“ace” 是 “abcde” 的一个子序列。
(1)数组
因为题目要求的回文子字符串的长度为3,所以我们只需要判断第1个字符和第3个字符是否相等,再找出两个字符中间有多少个不同字符,就是对应的回文子字符串的个数:
class Solution {
public int countPalindromicSubsequence(String s) {
int n = s.length(), ans = 0;
char[] sc = s.toCharArray();
for (int i = 0; i < 26; i++) { //遍历26个字母,找出回文个数
char t = (char)(i+'a');
int left = n; //找第一个字符, left = n 为了规避无sc[j]==t的情况
for (int j = 0; j < n; j++) {
if (sc[j] == t) {
left = j;
break;
}
}
int right = -1; // right = -1 为了规避无sc[j]==t的情况
for (int j = n - 1; j >= 0; j--) { //找第三个字符,和第一个相等
if (sc[j] == t) {
right = j;
break;
}
}
Set<Character> aux = new HashSet<>();
for (int j = left + 1; j < right; j++) { //判断两个相同字符中间有多少个不同的字符,计数即可
aux.add(sc[j]);
}
ans += aux.size();
}
return ans;
}
}
(2)set + map
思路与解法一一致,使用set跟map
- 遍历字符串,选择每一个字符s.charAt(i)作为回文子字符串的头字符(要求没有判断过这个字母开头的)。
- 找到与s.charAt(i)相同的最后一个字符的位置:j。
- 那么s.charAt(i)开头的回文子字符串的个数为(i, j)之间不同字符的个数。
class Solution {
public int countPalindromicSubsequence(String s) {
int len = s.length();
int count = 0;
Map<Character, Integer> map = new HashMap<>();
Set<Character> seen = new HashSet<>();
for (int i = 0; i < len; i++) {
map.put(s.charAt(i), i); //找到每一个字符的最后一个相同字符的位置:j
}
for (int i = 0; i < len - 2; i++) {
if (seen.contains(s.charAt(i))) continue; //已经遍历过的字符s.charAt(i),无需再次计算
Set<Character> set = new HashSet<>();
int end = map.get(s.charAt(i)); //到与s.charAt(i)相同的最后一个字符的位置:j。
for (int j = i + 1; j < end; j++) {
set.add(s.charAt(j)); //计算s.charAt(i)开头的回文子字符串的个数为(i, j)之间不同字符的个数
}
count += set.size();
seen.add(s.charAt(i));
}
return count;
}
}