#include <bits/stdc++.h>
// using namespace std;
using i64 = int_fast64_t;
#define repeat(i, a, b) for(int i = (a); (i) < (b); ++(i))
#define rep(i, n) repeat(i, 0, n)

namespace edamat {
using u64 = uint_fast64_t;

constexpr u64 M = (1UL << 61) - 1;
constexpr u64 POSITIVISER = M * 3;
constexpr u64 MASK30 = (1UL << 30) - 1;
constexpr u64 MASK31 = (1UL << 31) - 1;

class rolling_hash {
    static u64 get_base() {
        u64 z = (static_cast<uint64_t>((::std::chrono::system_clock::now()
                                            .time_since_epoch()
                                            .count()) &
                                       ((1LL << 32) - 1))) +
                0x9e3779b97f4a7c15;
        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9;
        z = (z ^ (z >> 27)) * 0x94d049bb133111eb;
        return z;
    }

    static u64& B() {
        static u64 B_ = (get_base()) % (M - 2) + 2;
        return B_;
    }
    static ::std::vector<u64>& p() {
        static ::std::vector<u64> p_{1, B()};
        return p_;
    }

    static inline u64 mul(u64 x, u64 y) {
        u64 a = x >> 31, b = x & MASK31, c = y >> 31, d = y & MASK31,
            e = b * c + a * d;
        return (a * c << 1) + b * d + ((e & MASK30) << 31) + (e >> 30);
    }

    static inline u64 calc_mod(u64 val) {
        val = (val & M) + (val >> 61);
        if(val > M) val -= M;
        return val;
    }

   public:
    ::std::vector<u64> hash;
    ::std::string str;
    explicit rolling_hash(const ::std::string& s) : str(s) {
        if(p().size() <= s.size()) {
            int l = p().size();
            p().resize(s.size() + 1);
            for(int i = l; i < p().size(); ++i) {
                p()[i] = calc_mod(mul(p()[i - 1], p()[1]));
            }
        }
        hash.resize(s.size() + 1, 0);
        for(int i = 0; i < s.size(); ++i) {
            hash[i + 1] = calc_mod(mul(hash[i], B()) + s[i]);
        }
    };

    u64 get(int l, int r) {
        return calc_mod(hash[r] + POSITIVISER - mul(hash[l], p()[r - l]));
    }

    // 最長共通接頭辞
    int get_lcp(int x, int y) {
        int len = ::std::min((int)size() - x, (int)size() - y) + 1;
        int l = 0, r = len;
        while(r - l > 1) {
            int m = (l + r) >> 1;
            if(get(x, x + m) != get(y, y + m))
                r = m;
            else
                l = m;
        }
        return l;
    }
    size_t size() {  // strのsizeを返す
        return str.size();
    }
};
}  // namespace edamat

int main() {
    int N;
    scanf("%d", &N);

    char s[N];
    scanf("%s", s);
    std::string S{s};
    edamat::rolling_hash rh(S);

    std::map<char, std::vector<int>> mp;
    for(int i = 0; i < N; ++i) {
        mp[S[i]].push_back(i);
    }
    int ok = 0;
    int ng = N;
    auto check = [&](int mid) -> bool {
        for(auto m : mp) {
            auto v = m.second;
            for(int i = 0; i < v.size(); ++i) {
                for(int j = i + 1; j < v.size(); ++j) {
                    if(v[i] + mid > v[j]) continue;
                    if(v[i] + mid > S.size() or v[j] + mid > S.size()) continue;
                    if(rh.get(v[i], v[i] + mid) == rh.get(v[j], v[j] + mid)) {
                        return true;
                    }
                }
            }
        }
        return false;
    };
    while(std::abs(ok - ng) > 1) {
        int mid = (ok + ng) / 2;
        if(check(mid)) {
            ok = mid;
        } else {
            ng = mid;
        }
    }
    printf("%d\n", ok);
};

Measured memory_bytes: 384