The only purpose of '#' is to reset the length of matched prefix.
I have a small change here. Instead of inserting a '#' between s and reverse(s) and calculating the KMP table for the concatenated string:
In this way we can get ride of concatenating strings and potential possibility that the original string contains a '#'.
Here is my source code: