Buggy python submission (verdict: Time Limit Exceeded):
N = int(input())
S = input()

checked = [[True for i in range(N)] for j in range(N)]
def ver(i, j, length):
    for f in range(length):
        if S[i+f] != S[j+f]: return False
    return True

def check(length):
    found = False
    for i in range(N):
        for j in range(i+length, N-length+1):
            if checked[i][j]:
                res = ver(i, j, length)
                if res:
                    found = True
                else:
                    checked[i][j] = False
    return found
            

for i in range(1, N):
    if not check(i):
        print(i - 1)
        break


Fixed submission:
N = int(input())
S = input()

def z_advanced(s):
    # Taken from https://ivanyu.me/blog/2013/10/15/z-algorithm/
    """An advanced computation of Z-values of a string."""
 
    Z = [0] * len(s)
    Z[0] = len(s)
 
    rt = 0
    lt = 0
 
    for k in range(1, len(s)):
        if k > rt:
            # If k is outside the current Z-box, do naive computation.
            n = 0
            while n + k < len(s) and s[n] == s[n+k]:
                n += 1
            Z[k] = n
            if n > 0:
                lt = k
                rt = k+n-1
        else:
            # If k is inside the current Z-box, consider two cases.
 
            p = k - lt  # Pair index.
            right_part_len = rt - k + 1
 
            if Z[p] < right_part_len:
                Z[k] = Z[p]
            else:
                i = rt + 1
                while i < len(s) and s[i] == s[i - k]:
                    i += 1
                Z[k] = i - k
 
                lt = k
                rt = i - 1
    return Z

best = 0
for i in range(N):
    lst = z_advanced(S[i:])
    for j, longest in enumerate(lst):
        best = max(best, min(j, longest))
print(best)

Buggy python submission (verdict: Time Limit Exceeded):
N = int(input())
S = input()

def ver(i, j, length):
    for f in range(length):
        if S[i+f] != S[j+f]: return False
    return True

def check(length):
    for i in range(N):
        for j in range(i+length, N-length+1):
            if ver(i, j, length): return True
    return False

def binarySearch(lo, hi):
    if lo >= hi:
        return lo
    mid = lo + (hi - lo + 1) // 2
    if check(mid):
        return binarySearch(mid, hi)
    else:
        return binarySearch(lo, mid - 1)

print(binarySearch(0, N//2))


Fixed submission:
N = int(input())
S = input()

def z_advanced(s):
    # Taken from https://ivanyu.me/blog/2013/10/15/z-algorithm/
    """An advanced computation of Z-values of a string."""
 
    Z = [0] * len(s)
    Z[0] = len(s)
 
    rt = 0
    lt = 0
 
    for k in range(1, len(s)):
        if k > rt:
            # If k is outside the current Z-box, do naive computation.
            n = 0
            while n + k < len(s) and s[n] == s[n+k]:
                n += 1
            Z[k] = n
            if n > 0:
                lt = k
                rt = k+n-1
        else:
            # If k is inside the current Z-box, consider two cases.
 
            p = k - lt  # Pair index.
            right_part_len = rt - k + 1
 
            if Z[p] < right_part_len:
                Z[k] = Z[p]
            else:
                i = rt + 1
                while i < len(s) and s[i] == s[i - k]:
                    i += 1
                Z[k] = i - k
 
                lt = k
                rt = i - 1
    return Z

best = 0
for i in range(N):
    lst = z_advanced(S[i:])
    for j, longest in enumerate(lst):
        best = max(best, min(j, longest))
print(best)