构建回文串检测

题目描述

给定一个字符串s,对s的子串进行检测。
每次检测,待检子串都可以表示为 queries[i] = [left, right, k]。我们可以重新排列子串 s[left], …, s[right],并从中选择最多k项替换成任何小写英文字母。 
如果在上述检测过程中,子串可以变成回文形式的字符串,那么检测结果为 true,否则结果为 false。
返回答案数组 answer[],其中 answer[i] 是第 i 个待检子串 queries[i] 的检测结果。
注意:在替换时,子串中的每个字母都必须作为 独立的 项进行计数,也就是说,如果 s[left..right] = “aaa” 且 k = 2,我们只能替换其中的两个字母。(另外,任何检测都不会修改原始字符串 s,可以认为每次检测都是独立的)

提示:

  • 1 <= s.length, queries.length <= 10^5
  • 0 <= queries[i][0] <= queries[i][1] < s.length
  • 0 <= queries[i][2] <= s.length
  • s 中只有小写英文字母

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/can-make-palindrome-from-substring

分析

我们可以做两个操作,即重新排列和替换最多k项为任意小写字母。既然可以重新排列,那么我们肯定想的是把重复的字母给他按照中心对称排列,剩下的就是出现单数的字母了,比如出现了3次b,那么我们可以取2个b对称排列,剩下一个b,到最后就会变成一个回文字符串和其余的个数为1的字母了,我们只要把这些单个的字母转换成回文就好。我们可以进行k次转换,假设单个字母的个数为n,由于这些字母互不相同,所以只要k >= n / 2就可以保证能够转换为回文,反之不行。
但是如果对每一个query都进行如上操作,会出现超时,所以我们对字符串s进行预处理,计算出0-i的子串包含字母c的次数,使用动态规划。

代码

实现如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import java.util.ArrayList;

class Solution {
public List<Boolean> canMakePaliQueries(String s, int[][] queries) {
// dp[i][j]表示字符串s的子串[0,i]包含小写字母(j + 'a')的个数
int[][] dp = new int[s.length()][26];
for (int i = 0; i < s.length(); i++) {
for (int j = 0; j < 26; j++) {
if (i == 0) {
dp[i][s.charAt(i) - 'a'] = 1;
} else {
dp[i][j] = dp[i - 1][j] + ((s.charAt(i) - 'a') == j? 1: 0);
}
}
}
List<Boolean> result = new ArrayList<Boolean>();
if (queries == null) {
return result;
}
for (int[] query : queries) {
int start = Math.min(Math.max(0, query[0]), s.length() - 1);
int end = Math.min(Math.max(0, query[1]), s.length() - 1);
int k = query[2];
if (k >= (end - start + 1) / 2) {
// 如果k大于等于子串长度的一半,直接判断为true
result.add(true);
continue;
}
// 所有奇数字符的个数
int count = 0;
for (int i = 0; i < 26; i++) {
int c = 0;
if (start == 0) {
c = dp[end][i];
} else {
// start-end的字符个数为dp[end] - dp[start - 1]
c = dp[end][i] - dp[start - 1][i];
}
if (c % 2 == 1) {
count++;
}
}
result.add(k >= count / 2);
}
return result;
}
}