蓝桥杯 全部都有的子序列 编程题

60 阅读2分钟

www.lanqiao.cn/problems/36…

image.png

用二分查找的思路

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

  int n,m;

  //定义数组大小
  const int N=1e5+10;


  // 定义数组 a 和 cnt.    a 用于存储输入的数据,cnt 用于存储每个数字出现的次数  
  int a[N];
  int cnt[1010];

  // 定义函数 check,用于检查长度为 len 的子序列是否包含 m 个新元素  
  bool check(int len)
  {
    // 初始化 cnt 数组为 0  
     memset(cnt,0,sizeof(cnt));
      
        // 初始化 k 为 0,用于记录新元素个数  
       int k=0;

         // 遍历长度为 len 的子序列  
       for(int i=1;i<=len;i++)
       {
            // 统计当前元素在子序列中出现的次数  
          cnt[a[i]]++;

          // 如果当前元素在子序列中第一次出现(即之前没有出现过)
          if(cnt[a[i]]==1) 

          // 新元素个数 k 加一  
          k++;

       // 如果新元素个数 k 等于目标值 m,说明长度为 len 的子序列中包含了 m 个新元素,返回 true  
       if(k==m) return true;    
       }
       for(int i=1;i+len<=n;i++){
            

              // l 为左端点,r 为右端点,初始值均为 i(即子序列的第一个元素)
            int l=i;
            int r=i+len;

              // 如果左端点和右端点对应的元素相等,则继续循环(因为已经包含在之前的遍历中了)  
            if(a[l]==a[r]) continue;  //如果找到了就不再--
            cnt[a[l]]--;


          // 对于右端点 a[r],其对应的新元素个数加一(因为新加入了一个新元素)
            if(cnt[a[l]]==0) k--;
            cnt[a[r]]++;

             // 如果右端点 a[r] 的新元素个数变为 1,说明其是新元素,新元素个数 k 加一   
            if(cnt[a[r]]==1) k++;
            

               // 如果新元素个数 k 等于目标值 m,说明长度为 len 的子序列中包含了 m 个新元素,返回 true  
            if(k==m) return true;
       }
       return false;
  }
int main()
{
  //请在此输入您的代码

 
  //关闭同步输入流; 
  ios::sync_with_stdio(false);
  cin.tie(0);


   cin>>n;//输入数据的个数
   m=0;
   for(int i=1;i<=n;i++)
  {
    cin>>a[i];
    if(cnt[a[i]]==0)m++;//i为0说明里面没有数据
    cnt[a[i]]++;
  }
  
    //开始二分查找
    int l=m,r=n;
    while(l<r)
    {
      int mid=(l+r)>>1;
      if(check(mid))
      {
        r= mid;  // //将搜索范围缩小为右半部分  
      }
      else
      { 
         l=mid+1;   //将搜索范围缩小为左半部分  
      }

    }   cout<<l<<endl;

  return 0;
}