力扣1177.构建回文串检测

由数据范围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)