Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -744,6 +744,7 @@
- 📄 [Rotation](src/main/java/com/thealgorithms/strings/Rotation.java)
- 📄 [StringCompression](src/main/java/com/thealgorithms/strings/StringCompression.java)
- 📄 [StringMatchFiniteAutomata](src/main/java/com/thealgorithms/strings/StringMatchFiniteAutomata.java)
- 📄 [SuffixArray](src/main/java/com/thealgorithms/strings/SuffixArray.java)
- 📄 [Upper](src/main/java/com/thealgorithms/strings/Upper.java)
- 📄 [ValidParentheses](src/main/java/com/thealgorithms/strings/ValidParentheses.java)
- 📄 [WordLadder](src/main/java/com/thealgorithms/strings/WordLadder.java)
Expand Down Expand Up @@ -1413,6 +1414,7 @@
- 📄 [RotationTest](src/test/java/com/thealgorithms/strings/RotationTest.java)
- 📄 [StringCompressionTest](src/test/java/com/thealgorithms/strings/StringCompressionTest.java)
- 📄 [StringMatchFiniteAutomataTest](src/test/java/com/thealgorithms/strings/StringMatchFiniteAutomataTest.java)
- 📄 [SuffixArrayTest](src/test/java/com/thealgorithms/strings/SuffixArrayTest.java)
- 📄 [UpperTest](src/test/java/com/thealgorithms/strings/UpperTest.java)
- 📄 [ValidParenthesesTest](src/test/java/com/thealgorithms/strings/ValidParenthesesTest.java)
- 📄 [WordLadderTest](src/test/java/com/thealgorithms/strings/WordLadderTest.java)
Expand Down
60 changes: 60 additions & 0 deletions src/main/java/com/thealgorithms/strings/SuffixArray.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package com.thealgorithms.strings;

import java.util.Arrays;

/**
* Suffix Array implementation in Java.
* Builds an array of indices that represent all suffixes of a string in sorted order.
* Wikipedia Reference: https://en.wikipedia.org/wiki/Suffix_array
* Author: Nithin U.
* Github: https://github.com/NithinU2802
*/

public final class SuffixArray {

private SuffixArray() {
}

public static int[] buildSuffixArray(String text) {
int n = text.length();
Integer[] suffixArray = new Integer[n];
int[] rank = new int[n];
int[] tempRank = new int[n];

// Initial ranking based on characters
for (int i = 0; i < n; i++) {
suffixArray[i] = i;
rank[i] = text.charAt(i);
}

for (int k = 1; k < n; k *= 2) {
final int step = k;

// Comparator: first by rank, then by rank + step
Arrays.sort(suffixArray, (a, b) -> {
if (rank[a] != rank[b]) {
return Integer.compare(rank[a], rank[b]);
}
int ra = (a + step < n) ? rank[a + step] : -1;
int rb = (b + step < n) ? rank[b + step] : -1;
return Integer.compare(ra, rb);
});

// Re-rank
tempRank[suffixArray[0]] = 0;
for (int i = 1; i < n; i++) {
int prev = suffixArray[i - 1];
int curr = suffixArray[i];
boolean sameRank = rank[prev] == rank[curr] && ((prev + step < n ? rank[prev + step] : -1) == (curr + step < n ? rank[curr + step] : -1));
tempRank[curr] = sameRank ? tempRank[prev] : tempRank[prev] + 1;
}

System.arraycopy(tempRank, 0, rank, 0, n);

if (rank[suffixArray[n - 1]] == n - 1) {
break;
}
}
return Arrays.stream(suffixArray).mapToInt(Integer::intValue).toArray();
}
}
44 changes: 44 additions & 0 deletions src/test/java/com/thealgorithms/strings/SuffixArrayTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.thealgorithms.strings;

import static org.junit.jupiter.api.Assertions.assertArrayEquals;

import org.junit.jupiter.api.Test;

class SuffixArrayTest {

@Test
void testEmptyString() {
int[] result = SuffixArray.buildSuffixArray("");
assertArrayEquals(new int[] {}, result, "Empty string should return empty suffix array");
}

@Test
void testSingleCharacter() {
int[] result = SuffixArray.buildSuffixArray("a");
assertArrayEquals(new int[] {0}, result, "Single char string should return [0]");
}

@Test
void testDistinctCharacters() {
int[] result = SuffixArray.buildSuffixArray("abc");
assertArrayEquals(new int[] {0, 1, 2}, result, "Suffixes already in order for distinct chars");
}

@Test
void testBananaExample() {
int[] result = SuffixArray.buildSuffixArray("banana");
assertArrayEquals(new int[] {5, 3, 1, 0, 4, 2}, result, "Suffix array of 'banana' should be [5,3,1,0,4,2]");
}

@Test
void testStringWithDuplicates() {
int[] result = SuffixArray.buildSuffixArray("aaaa");
assertArrayEquals(new int[] {3, 2, 1, 0}, result, "Suffix array should be descending indices for 'aaaa'");
}

@Test
void testRandomString() {
int[] result = SuffixArray.buildSuffixArray("mississippi");
assertArrayEquals(new int[] {10, 7, 4, 1, 0, 9, 8, 6, 3, 5, 2}, result, "Suffix array for 'mississippi' should match expected");
}
}