[leetcode]5175. Can Make Palindrome from Substring
一、题意
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.
二、题解
题意:给出一个字符串s,一个待检测串queries[i],每个queries[i]包含三个整数left、right、k。对子串s[left]....s[right]重新排列,同时最多可以更换k个字符,如果能排列成回文字符串则返回true,不然返回false;
样例解释:对于样例:s="abcda" , queries = [[3,3,0],[1,2,0],[0,3,1],[0,3,2],[0,4,1]]
- queries[0] : substring = "d", 直接是回文字符串,不必更换字符
- queries[1] : substring = "bc",重新排列不能变成回文字符串,最少更换1个字符才能变成回文字符串,然而k=0,所以返回false
- queries[2] : substring = "abcd", 重新排列不能变成回文字符串,最少更换2个字符才能变成回文字符串,然而k=1,所以返回fasle
- queries[3] : substring = "abcd", 重新排列不能变成回文字符串,最少更换1个字符才能变成回文,k=2大于1,所以返回true;
- queries[4] : substring = "abcda", 重新排列不能变成回文字符串,最少更换1个字符才能变成回文,k=1大于等于1,所以返回true;
题解:
首先对于是否可以重新排列组成回文串的判定:
可以得出,假如字符串中有n种字符为奇数,那么最少需要更换n/2个字符才能满足重新排列变成回文串。(证明略)
对于每个queries[i],可以统计对应子串中只有奇数个的字符的种类数,设为n,若n/2>k那么返回fasle,不然返回true。
如果使用遍历统计子串中奇数个的字符的种类数会超时,这里借鉴博客https://www.cnblogs.com/oldhands/p/11442566.html中的算法,使用dp[i][j]数组,表示截止下标i,字符'a'+j的个数,那么在统计s[left]...s[right]中各种字符的个数时使用dp[right][j]-dp[left-1][j]即可。
AC代码:
class Solution {
public:
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
vector<bool> ans;
vector<vector<int> > dp(s.length(), vector<int>(26, 0));
//dp[i][j] 截止i位置,字符a+j的个数
for(int i=0; i<s.length(); i++){
if(i==0){
dp[i][s[0]-'a'] ++;
continue;
}else{
for(int j=0; j<26; j++){
if(j==s[i]-'a'){
dp[i][j] = dp[i-1][j] +1;
}else{
dp[i][j] = dp[i-1][j];
}
//dp[j][]
}
//dp[i][s[i]-'a'] = dp[i-1][s[i]-'a']+1;
}
}
/*
for(int i=0; i<dp.size(); i++){
for(int j=0; j<dp[i].size(); j++){
cout<<dp[i][j]<<" ";
}
cout<<endl;
}
*/
for(int i=0; i<queries.size(); i++){
//string temp = s.substr(queries[i][0], queries[i][1]-queries[i][0]+1);
int left = queries[i][0];
int right = queries[i][1];
int k = queries[i][2];
if(left==right || k>=(right-left+1)){
ans.push_back(true);
//cout<<"i:"<<i<<endl;
continue;
}
int cnt = 0;
for(int i=0; i<26; i++){
if(left==0){
if(dp[right][i] % 2 == 1){
cnt ++;
}
}else{
if((dp[right][i]-dp[left-1][i])%2 == 1){
cnt ++;
}
}
}
cnt /= 2;
//cout<<"i:"<<i<<" ";
//cout<<cnt<<endl;
if(cnt > k){
ans.push_back(false);
}else{
ans.push_back(true);
}
}
return ans;
}
};
浙公网安备 33010602011771号