Add comments.

This commit is contained in:
Oleksii Trekhleb 2018-06-21 17:48:35 +03:00
parent 5bdcbb397d
commit 81d17bc4f9

View File

@ -6,39 +6,95 @@ const SEPARATOR = '$';
* @return {number[]} * @return {number[]}
*/ */
function buildZArray(zString) { function buildZArray(zString) {
const zArray = new Array(zString.length); // Initiate zArray and fill it with zeros.
const zArray = new Array(zString.length).fill(null).map(() => 0);
let left = 0; // Z box boundaries.
let right = 0; let zBoxLeftIndex = 0;
let k = 0; let zBoxRightIndex = 0;
for (let i = 1; i < zString.length; i += 1) { // Position of current zBox character that is also a position of
if (i > right) { // the same character in prefix.
left = i; // For example:
right = i; // Z string: ab$xxabxx
// Indices: 012345678
// Prefix: ab.......
// Z box: .....ab..
// Z box shift for 'a' would be 0 (0-position in prefix and 0-position in Z box)
// Z box shift for 'b' would be 1 (1-position in prefix and 1-position in Z box)
let zBoxShift = 0;
while (right < zString.length && zString[right - left] === zString[right]) { // Go through all characters of the zString.
right += 1; for (let charIndex = 1; charIndex < zString.length; charIndex += 1) {
if (charIndex > zBoxRightIndex) {
// We're OUTSIDE of Z box. In other words this is a case when we're
// starting from Z box of size 1.
// In this case let's make current character to be a Z box of length 1.
zBoxLeftIndex = charIndex;
zBoxRightIndex = charIndex;
// Now let's go and check current and the following characters to see if
// they are the same as a prefix. By doing this we will also expand our
// Z box. For example if starting from current position we will find 3
// more characters that are equal to the ones in the prefix we will expand
// right Z box boundary by 3.
while (
zBoxRightIndex < zString.length &&
zString[zBoxRightIndex - zBoxLeftIndex] === zString[zBoxRightIndex]
) {
// Expanding Z box right boundary.
zBoxRightIndex += 1;
} }
zArray[i] = right - left; // Now we may calculate how many characters starting from current position
right -= 1; // are are the same as the prefix. We may calculate it by difference between
// right and left Z box boundaries.
zArray[charIndex] = zBoxRightIndex - zBoxLeftIndex;
// Move right Z box boundary left by one position just because we've used
// [zBoxRightIndex - zBoxLeftIndex] index calculation above.
zBoxRightIndex -= 1;
} else { } else {
k = i - left; // We're INSIDE of Z box.
if (zArray[k] < (right - i) + 1) {
zArray[i] = zArray[k]; // Calculate corresponding Z box shift. Because we want to copy the values
// from zArray that have been calculated before.
zBoxShift = charIndex - zBoxLeftIndex;
// Check if the value that has been already calculated before
// leaves us inside of Z box or it goes beyond the checkbox
// right boundary.
if (zArray[zBoxShift] < (zBoxRightIndex - charIndex) + 1) {
// If calculated value don't force us to go outside Z box
// then we're safe and we may simply use previously calculated value.
zArray[charIndex] = zArray[zBoxShift];
} else { } else {
left = i; // In case if previously calculated values forces us to go outside of Z box
while (right < zString.length && zString[right - left] === zString[right]) { // we can't safely copy previously calculated zArray value. It is because
right += 1; // we are sure that there is no further prefix matches outside of Z box.
// Thus such values must be re-calculated and reduced to certain point.
// To do so we need to shift left boundary of Z box to current position.
zBoxLeftIndex = charIndex;
// And start comparing characters one by one as we normally do for the case
// when we are outside of checkbox.
while (
zBoxRightIndex < zString.length &&
zString[zBoxRightIndex - zBoxLeftIndex] === zString[zBoxRightIndex]
) {
zBoxRightIndex += 1;
} }
zArray[i] = right - left; zArray[charIndex] = zBoxRightIndex - zBoxLeftIndex;
right -= 1;
zBoxRightIndex -= 1;
} }
} }
} }
// Return generated zArray.
return zArray; return zArray;
} }