Created
April 22, 2015 05:09
-
-
Save keif/763b6d725e23bb1b91f5 to your computer and use it in GitHub Desktop.
A VERY INCOMPLETE AND UNTESTED JavaScript code rip of Manacher's algorithm. I want to get this into node to actually play with it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Computes the longest palindromic substring in linear time | |
* using Manacher's algorithm. | |
* | |
* Credits: The code is lifted from the following excellent reference | |
* http://www.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html | |
**/ | |
var Manacher = (function () { | |
var palindromic = [], // p[i] = length of longest palindromic substring of t, centered at i | |
string, // original string | |
transform, // transformed string | |
manacher, | |
preprocess, | |
longestPalindromicSubstring, | |
main; | |
manacher = function (string) { | |
this.string = string; | |
transform = preprocess(string); | |
palindromic = [transform.length]; | |
var center = 0, | |
right = 0; | |
for (var i = 1; i < transform.length - 1; i++) { | |
var mirror = 2 * center - i; | |
if (right > i) { | |
palindromic[i] = Math.min(right - i, palindromic[mirror]); | |
} | |
// attempt to expand palindrome centered at i | |
while (transform[i + (1 + palindromic[i])] === transform[i - (1 + palindromic[i])]) { | |
palindromic[i]++; | |
} | |
// if palindrome centered at i expands past right, | |
// adjust center based on expanded palindrome. | |
if (i + palindromic[i] > right) { | |
center = i; | |
right = i + palindromic[i]; | |
} | |
} | |
}; | |
// Transform s into t. | |
// For example, if s = "abba", then t = "$#a#b#b#a#@" | |
// the # are interleaved to avoid even/odd-length palindromes uniformly | |
// $ and @ are prepended and appended to each end to avoid bounds checking | |
preprocess = function (s) { | |
var t = [s.length * 2 + 3]; | |
t[0] = '$'; | |
t[s.length * 2 + 2] = '@'; | |
for (var i = 0; i < s.length; i++) { | |
t[2 * i + 1] = '#'; | |
t[2 * i + 2] = s.charAt(i); | |
} | |
t[s.length * 2 + 1] = '#'; | |
return t; | |
}; | |
// longest palindromic substring | |
longestPalindromicSubstring = function (i) { | |
if (!i) { | |
var length = 0, // length of longest palindromic substring | |
center = 0; // center of longest palindromic substring | |
for (var i = 1; i < palindromic.length - 1; i++) { | |
if (palindromic[i] > length) { | |
length = palindromic[i]; | |
center = i; | |
} | |
} | |
return string.substring((center - 1 - length) / 2, (center - 1 + length) / 2); | |
} else { | |
i = i + 2; | |
var length = palindromic[i], | |
center = i; | |
return string.substring((center - 1 - length) / 2, (center - 1 + length) / 2); | |
} | |
} | |
// test client | |
main = function(args) { | |
var s = args[0], | |
manacher = this.manacher(s); | |
console.log(this.longestPalindromicSubstring()); | |
for (var i = 0; i < 2 * s.length; i++) { | |
console.log(i + ": " + this.longestPalindromicSubstring(i)); | |
} | |
}; | |
return { | |
manacher: manacher, | |
preprocess: preprocess, | |
longestPalindromicSubstring: longestPalindromicSubstring, | |
init: main | |
} | |
})(Manacher); | |
var palindrome = "tacocat"; | |
Manacher.init(palindrome); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment