Decompresses a list of integers back into a string using the LZW algorithm. @param compressed A list of integers representing the compressed data. Can be null. @return The original, uncompressed string. Returns an empty string if the input is null or empty.
(List<Integer> compressed)
| 97 | * input is null or empty. |
| 98 | */ |
| 99 | public static String decompress(List<Integer> compressed) { |
| 100 | if (compressed == null || compressed.isEmpty()) { |
| 101 | return ""; |
| 102 | } |
| 103 | |
| 104 | // Initialize dictionary with single characters (ASCII 0-255) |
| 105 | int dictSize = 256; |
| 106 | Map<Integer, String> dictionary = new HashMap<>(); |
| 107 | for (int i = 0; i < dictSize; i++) { |
| 108 | dictionary.put(i, "" + (char) i); |
| 109 | } |
| 110 | |
| 111 | // Decompress the first code |
| 112 | String w = "" + (char) (int) compressed.removeFirst(); |
| 113 | StringBuilder result = new StringBuilder(w); |
| 114 | |
| 115 | for (int k : compressed) { |
| 116 | String entry; |
| 117 | if (dictionary.containsKey(k)) { |
| 118 | // The code is in the dictionary |
| 119 | entry = dictionary.get(k); |
| 120 | } else if (k == dictSize) { |
| 121 | // Special case for sequences like "ababab" |
| 122 | entry = w + w.charAt(0); |
| 123 | } else { |
| 124 | throw new IllegalArgumentException("Bad compressed k: " + k); |
| 125 | } |
| 126 | |
| 127 | result.append(entry); |
| 128 | |
| 129 | // Add new sequence to the dictionary |
| 130 | dictionary.put(dictSize++, w + entry.charAt(0)); |
| 131 | |
| 132 | w = entry; |
| 133 | } |
| 134 | return result.toString(); |
| 135 | } |
| 136 | } |