【二分最短区间长度 最短区间包含字符串所有字符】 我全都要

题意

给定一个字符串,要求在整个字符串出现过的字母在选取的区间中都出现至少\(k\)次,求最短区间有多短

题解

因为是最短区间所以用在二分区间的长度时候如果二分的中点表示的区间长度满足就缩小
每个长度都从前往后遍历所有的长度为\(len\)的不重复子区间,

  • 如果有满足条件的即当前二分的答案满足继续缩小

  • 如果不满足就扩大

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
#define ll long long
const int N=1e5+10;
string str;
int n,k,_;
unordered_map<char,int>rec,ans;
bool judge()
{
   for(int i='a';i<='z';i++)
   {
      char c=(char)i;
      if(!rec[c]) continue;
      if(ans[c]<k) return 0;
   }
   return 1;
}
bool check(int len)
{
   ans.clear();
   int l=0,r=len-1;
   rep(i,l,r+1)
      ans[str[i]]++;
   while(r<n){
      if(judge())
         return true;
      ans[str[l]]--;
      l++;
      r++;
      if(r<n)
       ans[str[r]]++;
   }
   return false;
}

int main()
{
   for(cin>>_;_;_--)
   {
      rec.clear();
      cin>>n>>k;
      cin>>str;
      if(!k) 
      {
         puts("0");continue;
      }
      rep(i,0,n)
      {
         rec[str[i]]++;
      }
      bool exist=1;
      for(int i='a';i<='z';i++) 
      {
         char c=(char)i;
         if (rec[c] > 0 && rec[c] < k)
         {
            exist=0;
            break;
         }
      }
      if(exist) 
      {
         int l = 1, r = n;
         while (l < r) 
         {
            int mid = l + r >> 1;
            if (check(mid))    r=mid;
            else    l=mid+1;
         }
         cout<<l<<endl;
      }
      else
         puts("-1");
   }
}
posted @ 2020-05-26 00:31  Hyx'  阅读(250)  评论(0编辑  收藏  举报