Given a string s
, we make queries on substrings of s
.
For each query queries[i] = [left, right, k]
, we may rearrange the substring s[left], ..., s[right]
, and then choose up to k
of them to replace with any lowercase English letter.
If the substring is possible to be a palindrome string after the operations above, the result of the query is true
. Otherwise, the result is false
.
Return an array answer[]
, where answer[i]
is the result of the i
-th query queries[i]
.
Note that: Each letter is counted individually for replacement so if for example s[left..right] = "aaa"
, and k = 2
, we can only replace two of the letters. (Also, note that the initial string s
is never modified by any query.)
Example :
Input: s = "abcda", queries = [[3,3,0],[1,2,0],[0,3,1],[0,3,2],[0,4,1]]
Output: [true,false,false,true,true]
Explanation:
queries[0] : substring = "d", is palidrome.
queries[1] : substring = "bc", is not palidrome.
queries[2] : substring = "abcd", is not palidrome after replacing only 1 character.
queries[3] : substring = "abcd", could be changed to "abba" which is palidrome. Also this can be changed to "baab" first rearrange it "bacd" then replace "cd" with "ab".
queries[4] : substring = "abcda", could be changed to "abcba" which is palidrome.
Constraints:
1 <= s.length, queries.length <= 10^5
0 <= queries[i][0] <= queries[i][1] < s.length
0 <= queries[i][2] <= s.length
s
only contains lowercase English letters.
题解:
没注意可以rearrange。。。
比如lunu, [0, 3, 1],可以把它变为luun,然后变为nuun就行。
记录前i个字符中所有字母出现次数,然后偶数可以配对,奇数需要改一下,最终总数为所有出现字母中奇数的数量除以2(两个不同只要改一次)。
class Solution {
public:
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
int n = queries.size();
int l = s.length();
vector<bool> res;
vector<vector<int>> cnt(l + 1, vector<int>(26, 0));
for (int i = 1; i <= l; i++) {
cnt[i] = cnt[i - 1];
cnt[i][s[i - 1] - 'a'] = cnt[i - 1][s[i - 1] - 'a'] + 1;
}
for (int i = 0; i < n; i++) {
int dif = 0;
for (int j = 0; j < 26; j++) {
if ((cnt[queries[i][1] + 1][j] - cnt[queries[i][0]][j]) % 2 != 0){
dif++;
}
}
dif /= 2;
if (queries[i][2] >= dif) {
res.push_back(true);
}
else {
res.push_back(false);
}
}
return res;
}
};
讨论区一个强大的解法:
由于只有26个字母,并且只需记录他们出现的次数是奇数还是偶数,那么可以用位运算来优化。
算法思路同上,记录前i个字符中每个字母出现的次数是奇还是偶,每个字母出现就对其位置进行异或,则奇数次位为1,偶数次位为0,最后按位判断子串中每个字母出现次数是否为奇数。
class Solution {
public:
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
int n = queries.size();
int l = s.length();
vector<bool> res;
vector<int> cnt(l + 1, 0);
for (int i = 1; i <= l; i++) {
cnt[i] = cnt[i - 1] ^ (1 << s[i - 1] - 'a');
}
for (int i = 0; i < n; i++) {
int dif = 0;
int x = cnt[queries[i][1] + 1] ^ cnt[queries[i][0]];
while (x != 0) {
if (x & 1 != 0) {
dif++;
}
x >>= 1;
}
dif /= 2;
if (queries[i][2] >= dif) {
res.push_back(true);
}
else {
res.push_back(false);
}
}
return res;
}
};