
由数据范围10^5知,我们知道暴力注定不好使,我写的暴力代码如下:
c++
class Solution {
public:
int a[26];
bool tostart(string& s,int l,int r)
{
while(l<r)
{
if(s[l]==s[r])
{
l++;
r--;
}
else
{
return false;
}
}
return true;
}
int howmanydifferent(const string& s,int l,int r)
{
memset(a,0,sizeof(a));
int cnt=0;
for(int i=l;i<=r;i++)
{
a[s[i]-'a']++;
}
for(int i=0;i<26;i++)
{
if(a[i]==1)
{
cnt++;
}
}
return cnt/2;
}
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
vector<bool> ans;
for(int i=0;i<queries.size();i++)
{
int l=queries[i][0];
int r=queries[i][1];
int k=queries[i][2];
//如何高效的判断一个子串是不是回文串
//判断本身是不是回文串
//判断在k次内变化后是不是回文串
if(tostart(s,l,r))
{
ans.push_back(true);
}
else
{
//如何在k次变化内判断是不是回文串
//那我们就看它在有几个不一样的子串
//没有考虑重新排列,
//可是如果考虑重新排列的话
// huun
//我们只需要统计有几个不一样的字符就行
int x=howmanydifferent(s,l,r);
if(x<=k)
{
ans.push_back(true);
}
else
{
ans.push_back(false);
}
}
}
return ans;
}
};
这样的思路本身就存在错误,思考这个重新排列+回文串的问题,切入点是看字母出现的奇偶次,如果一个字母出现偶次,那么就不需要排列变化,出现奇数次,如果是三次以上,两两配对,只会剩下一个,剩下的会和其他出现奇数次的字符匹配,两两匹配,这样需要变化的次数实际上就是出现奇数次字母的总个数X,X/2即可;
那么我们需要统计一个范围内出现奇数次字母的总个数,可以用前缀和来进行快速的统计。
那么代码如下:
c++
class Solution {
public:
int sum[100005][26];
vector<bool> canMakePaliQueries(string s, vector<vector<int>>& queries) {
int n=s.size();
//对于这一题而言,只要是偶数个都可以均分成两部分
//如果有奇数个,那么必须对多出来的进行讨论
//如果只有一个字符出现奇数次,那么可以得到一个回文串。
//如果以两种字母出现奇数次,由于多出的一个a和b无法组成回文串,
//可以把其中一个修改
//如果三个字母出现奇数次,把一个b改成c,就转化成只有a出现奇数次
//我们可以发现只需要当有m种字母出现奇数次,只需修改m/2次。
for(int i=0;i<s.size();i++)
{
for(int j=0;j<26;j++)
{
sum[i+1][j]=sum[i][j];
}
sum[i+1][s[i]-'a']++;
}
vector<bool> ans;
for(int i=0;i<queries.size();i++)
{
int l=queries[i][0];
int r=queries[i][1];
int k=queries[i][2];
int x=0;
for(int j=0;j<26;j++)
{
x+=(sum[r+1][j]-sum[l][j])%2;
//这统计的是在这个位置中,出现次数
//一个字母出现的次数,比如是5%2=1
}
if(x/2<=k)
{
ans.push_back(true);
}
else
{
ans.push_back(false);
}
}
return ans;
}
};
时间复杂度为O(26^n)