#include<bits/stdc++.h>
#define X first
#define Y second
#define pb emplace_back
#define FOR(i,a,b) for(int (i)=(a);i<(b);++(i))
#define EFOR(i,a,b) for(int (i)=(a);i<=(b);++(i))
#define rep(X,Y) for (int (X) = 0;(X) < (Y);++(X))
#define REP rep
#define rrep(X,Y) for (int (X) = (Y)-1;(X) >=0;--(X))
#define all(X) (X).begin(),(X).end()
#define eb emplace_back

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
typedef ll LL;
typedef pii PII;
typedef pll PLL;
const ll MOD=1e9+7;

#define rall(X) (X).rbegin(),(X).rend()
#define UNIQUE(X) (X).erase(unique(all(X)),(X).end())
#define reps(X,S,Y) for (int (X) = S;(X) < (Y);++(X))
#define rreps(X,S,Y) for (int (X) = (Y)-1;(X) >= (S);--(X))
template<class T> inline bool MX(T &l,const T &r){return l<r?l=r,1:0;}
template<class T> inline bool MN(T &l,const T &r){return l>r?l=r,1:0;}

template<class T> using vv = vector<vector<T>>;
using vi = vector<int>;
template <class T>
struct LCP{
	int n;
	vi vs, isa, lcp;
	LCP(const T &s, const vi &sa):n(sa.size()),vs(n),isa(n),lcp(n - 1){
		rep(i, n-1) vs[i] = s[i];
		rep(i, n) isa[sa[i]] = i;
		int h = 0, j;
		rep(i, n)if((j = isa[i]) > 0){
			while(vs[sa[j] + h] == vs[sa[j-1] + h]) h++;
			lcp[j-1] = h;
			if(h > 0) --h;
		}
	}
	int operator[](int i) const{
		return lcp[i];
	}
};


struct SuffixArray{
	template <bool End, class T>
	vi compute_buckets(const T *s, int n, int k) const {
		vi buckets(k);
		rep(i, n) ++buckets[s[i]];
		int sum = 0;
		rep(i, k){
			sum += buckets[i];
			buckets[i] = (End ? sum : (sum - buckets[i]));
		}
		return buckets;
	}
	template <class T>
	void induce_sa_l(int *sa, const T *s, int n, int k, const vi &ls) const{
		vi buckets(compute_buckets<false>(s, n, k));
		rep(i, n){
			const int j = sa[i] - 1;
			if(j >= 0 && !ls[j]){ sa[buckets[s[j]]++] = j; }
		}
	}
	template <class T>
	void induce_sa_s(int *sa, const T *s, int n, int k, const vi &ls) const{
		vi buckets(compute_buckets<true>(s, n, k));
		rrep(i, n){
			const int j = sa[i] - 1;
			if(j >= 0 && ls[j]){ sa[--buckets[s[j]]] = j; }
		}
	}
	bool is_lms(const vi& ls, int i)const {
		return i>0 && !ls[i-1] && ls[i];
	}
	
	template <class T>
	void sa_is(int *sa, const T *s, int n) const{
		vi ls(n); // 0:L 1:S
		ls[n-1] = 1;
		rrep(i, n-1) ls[i] = (s[i] != s[i+1]) ? s[i] < s[i+1] : ls[i+1];
		const int k = (int)*std::max_element(s, s + n) + 1;
		vi buckets = compute_buckets<true>(s, n, k);
		rep(i, n) sa[i] = -1;
		rep(i, n) if(is_lms(ls, i)) sa[--buckets[s[i]]] = i;
		induce_sa_l(sa, s, n, k, ls);
		induce_sa_s(sa, s, n, k, ls);
		int m = 0;
		rep(i, n) if(is_lms(ls, sa[i])) sa[m++] = sa[i];
		for(int i=m;i<n;i++) sa[i] = -1;
		int num = 0, prev = -1;
		rep(i, m){
			int p = sa[i], diff = 0;
			rep(d, n){
				const int l = p+d, r = prev + d;
				if(prev < 0 || s[l] != s[r] || ls[l] != ls[r]){
					diff = 1;
					break;
				}else if(d > 0 && (is_lms(ls, l) || is_lms(ls, r))){
					break;
				}
			}
			if(diff){
				num ++;
				prev = p;
			}
			p = (p-(p&1))/2;
			sa[m+p] = num-1;
		}
		for(int i=n-1, j=n-1;i>=m;i--) if(sa[i] >= 0) sa[j--]=sa[i];
		int *reduced_s = sa+n-m;
		if(num < m) sa_is(sa, reduced_s, m);
		else rep(i, m) sa[reduced_s[i]] = i;
		buckets = compute_buckets<true>(s, n, k);
		int j=0;
		rep(i, n)if(is_lms(ls, i)) reduced_s[j++] = i;
		rep(i, m) sa[i] = reduced_s[sa[i]];
		for(int i=m;i<n;i++) sa[i] = -1;
		rrep(i, m){
			const int j = sa[i];
			sa[i] = -1;
			sa[--buckets[s[j]]] = j;
		}
		induce_sa_l(sa, s, n, k, ls);
		induce_sa_s(sa, s, n, k, ls);
	}
	
	vi sa;

	template <class T>
	vi sa_is(const T &s) const {
		if(s.size() == 0){ return vi(1); }
		const int n = s.size() + 1;
		vi vs(n), sa(n);;
		rep(i, n-1){ vs[i] = s[i]; }
		sa_is(&sa[0], &vs[0], n);
		return sa;
	}
	template <class T>
	explicit SuffixArray(const T &s):sa(sa_is(s)){}
	size_t size() const { return sa.size(); }
	int operator[](int i) const { return sa[i]; }
};


string S;

signed main(){
  ios_base::sync_with_stdio(false);
  cout<<fixed<<setprecision(0);

  int N;
  cin >> N;
  cin >> S;
  SuffixArray SA(S);
  LCP<string> lcp(S, SA.sa);
  int ans = 0;
  rep(i, N) {
    int t = lcp[i];
    MX(ans, min(abs(SA[i]-SA[i+1]), t));
    reps(j, i+1, N) {
      MN(t, lcp[j]);
      MX(ans, min(abs(SA[i]-SA[j+1]), t));
    }
  }
  cout << ans << endl;
}


Measured memory_bytes: 384