diff --git a/src/algorithms/bwt/bwtDecode.ts b/src/algorithms/bwt/bwtDecode.ts index a17eb71..796496e 100644 --- a/src/algorithms/bwt/bwtDecode.ts +++ b/src/algorithms/bwt/bwtDecode.ts @@ -1,23 +1,52 @@ +import { createFrequencyMap } from "../../common/utils"; import { END_OF_STRING } from "./utils/constants"; /** * Decodes a string that was encoded using the Burrows-Wheeler Transform (BWT). * - * The function reconstructs the original string by progressively building up the rows of the sorted - * permutation table from the BWT string, and then retrieving the row at the specified index. + * The function reconstructs the original string from its BWT representation by: + * + * 1. Building a frequency table of characters from the BWT string. + * 2. Creating a table that maps each character to its first occurrence in the sorted version of the BWT string. + * 3. Generating a `nextRow` table that helps in reconstructing the original string by indicating the position of each character in the sorted table. + * 4. Using the `nextRow` table and starting from the provided index to rebuild the original string in reverse order. + * + * Instead of concatenating strings repeatedly, the function constructs the result using an array and then converts it to a string for improved performance. * * @param {string} bwt - The Burrows-Wheeler Transform (BWT) encoded string to decode. * @param {number} index - The index of the original string in the sorted permutation table. * @returns {string} The decoded original string. */ -export function bwtDecode(bwt: string, index: number): string { - const length = bwt.length; - const table = Array.from({ length }, () => ""); +export function bwtDecode(input: string, index: number): string { + const length = input.length; + + const frequencyTable = createFrequencyMap(input); + const sortedChars = Array.from(frequencyTable.keys()).sort(); + + // the first accurance of a char + // in sorted bwt string + const firstOccurrenceTable = new Map(); + let position = 0; + for (const char of sortedChars) { + firstOccurrenceTable.set(char, position); + position += frequencyTable.get(char)!; + } + + const charCountTable = new Map(); + const charsIndexesInSortedInput = Array(length).fill(0); for (let i = 0; i < length; i++) { - for (let j = 0; j < length; j++) { - table[j] = bwt[j] + table[j]; - } - table.sort(); + const char = input[i]; + charCountTable.set(char, (charCountTable.get(char) || 0) + 1); + charsIndexesInSortedInput[i] = + firstOccurrenceTable.get(char)! + charCountTable.get(char)! - 1; + } + + const output = new Array(length); + let currentIndex = index; + for (let i = length - 1; i >= 0; i--) { + output[i] = input[currentIndex]; + currentIndex = charsIndexesInSortedInput[currentIndex]; } - return table[index].replace(END_OF_STRING, ""); + + return output.join("").replace(END_OF_STRING, ""); }