class Solution:
    def shortestPalindrome(self, s: str) -> str:
        rev = s[::-1]
        n = len(s)
        for i in range(n):
            if s[0:n-i] == rev[i:]: # longest prefix substring which is palindrom 
                return rev[0:i]+s 
        return ""

KMP solution

class Solution:
    def shortestPalindrome(self, s: str) -> str:
        """ tc O(N) sc O(N)
        main idea: if in t at index i we find a substring equals s, return t[:i+1]
        """
        reverse_s = s[::-1]
        ns =  s + '#' + reverse_s
        nxt = [0] * len(ns)
        pre, cur = 0,1
        while cur <len(ns):
            if ns[cur] == ns[pre]:
                nxt[cur] = pre + 1 
                cur += 1 
                pre += 1 
            elif pre > 0:
                pre = nxt[pre-1]
            else:
                cur += 1
        #print(nxt)
        #print(ns)
        max_len = nxt[len(ns)-1] # max common substring of ns's prefix and suffix 
        return reverse_s[:len(reverse_s)-max_len]+s 

reference

TODO Rabin-Karp solution