/*
#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx,avx2,fma")
*/
#include<bits/stdc++.h>
using namespace std;
 
 
#ifndef ONLINE_JUDGE
  #include "prettyprint.hpp"
#else 
#define dbg(...)
#endif
 
/*
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace __gnu_pbds;
*/
 
#define ar array 
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define sz(v) int((v).size())
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define rep(i,a,b) for(int i = a; i < b; i++)
#define deb(x) cout << #x << "=" << x << endl
#define PI 3.1415926535897932384626
#define PQ(type) priority_queue<type>
#define PQD(type) priority_queue<type,vector<type>,greater<type> > // min heap
#define runtime() ((double)clock() / CLOCKS_PER_SEC)
#define endl '\n'
 
//typedef tree<int,null_type,less<int>,rb_tree_tag, tree_order_statistics_node_update> indexed_set; // use less_equal for multiset
// order_of_key (val): returns the no. of values less than val
// find_by_order (k): returns the iterator to kth largest element.(0-based)
 
typedef long long ll; 
typedef long double ld; 
typedef vector<int> vi;
typedef vector<ll> vll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
 
 
const  int mxN = 2e5+5;
const  long long INF= 1e18;
const long long mod= 1e9 + 7;
 
mt19937 RNG(chrono::steady_clock::now().time_since_epoch().count());
#define SHUF(v) shuffle(all(v), RNG);
// Use mt19937_64 for 64 bit random numbers.
 
 
void solve() {
  int n, k;
  cin >> n >> k;
  string s;
  cin >> s;
 
  int l = 1, r = n, ans = 0;
 
  auto check = [&] (int val) {
    vector<vi> pos(k, vi(n + 1));
    vi dp(1 << k, 1e9);
 
    rep(i, 0, k) {
      int cur = 0;
      pos[i][n] = 1e9;
      for(int j = n; j >= 1; j--) {
        if(j < n) pos[i][j] = pos[i][j + 1];
        if(cur >= val) {
          pos[i][j] = j + val;
        }
        if(s[j - 1] == (i + 'a') || s[j - 1] == '?') cur++;
        else cur = 0;
      }
      if(cur >= val) pos[i][0] = val;
      else pos[i][0] = pos[i][1];
    }
 
    dp[0] = 0;
 
    rep(mask, 1, 1 << k) {
      rep(j, 0, k) {
        if(mask & (1 << j)) {
          int temp = mask ^ (1 << j);
          if(dp[temp] != 1e9) {
            dp[mask] = min(dp[mask], pos[j][dp[temp]]);
          }
        }
      }
    }
 //   dbg(val, dp, pos);
    return (dp[(1 << k) - 1] <= n);
 
  };
 
  while(l <= r) {
    int mid = (l + r) / 2;
    if(check(mid)) {
      ans = max(ans, mid);
      l = mid + 1;
    }
    else r = mid - 1;
  }
  cout << ans << endl;
}
 
 
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
 
int t = 1;
while(t--) {
solve();
}
}