Trouver la plus longue sous-chaîne sans caractères répétés

Trouver la plus longue sous-chaîne sans caractères répétés

1. Vue d'ensemble

Dans ce didacticiel, comparez différentes manières de rechercher la plus longue sous-chaîne de lettres uniques en utilisant Java. Par exemple, la plus longue sous-chaîne de lettres uniques dans «CODINGISAWESOME» est «NGISAWE».

2. Approche de la force brute

Commençons par une approche naïve. Pour commencer,we can examine each substring whether it contains unique characters:

String getUniqueCharacterSubstringBruteForce(String input) {
    String output = "";
    for (int start = 0; start < input.length(); start++) {
        Set visited = new HashSet<>();
        int end = start;
        for (; end < input.length(); end++) {
            char currChar = input.charAt(end);
            if (visited.contains(currChar)) {
                break;
            } else {
                visited.add(currChar);
            }
        }
        if (output.length() < end - start + 1) {
            output = input.substring(start, end);
        }
    }
    return output;
}

Puisqu'il y an*(n+1)/2 sous-chaînes possibles,the time complexity of this approach is O(n^2).

3. Approche Optimisée

Voyons maintenant une approche optimisée. Nous commençons à parcourir la chaîne de gauche à droite et maintenons la trace de:

  1. la sous-chaîne courante avec des caractères non répétitifs à l'aide d'un indexstart etend

  2. la plus longue sous-chaîne non répétitiveoutput

  3. une table de recherche de déjàvisited caractères

String getUniqueCharacterSubstring(String input) {
    Map visited = new HashMap<>();
    String output = "";
    for (int start = 0, end = 0; end < input.length(); end++) {
        char currChar = input.charAt(end);
        if (visited.containsKey(currChar)) {
            start = Math.max(visited.get(currChar)+1, start);
        }
        if (output.length() < end - start + 1) {
            output = input.substring(start, end + 1);
        }
        visited.put(currChar, end);
    }
    return output;
}

Pour chaque nouveau personnage, nous le recherchons dans les personnages déjà visités. Si le caractère a déjà été visité et fait partie de la sous-chaîne actuelle avec des caractères non répétitifs, nous mettons à jour l'index de début. Sinon, nous continuerons à parcourir la chaîne.

Puisque nous parcourons la chaîne une seule fois,the time complexity will be linear, or O(n).

Cette approche est également connue sous le nom desliding window pattern.

4. Essai

Enfin, testons minutieusement notre implémentation pour nous assurer qu'elle fonctionne:

@Test
void givenString_whenGetUniqueCharacterSubstringCalled_thenResultFoundAsExpected() {
    assertEquals("", getUniqueCharacterSubstring(""));
    assertEquals("A", getUniqueCharacterSubstring("A"));
    assertEquals("ABCDEF", getUniqueCharacterSubstring("AABCDEF"));
    assertEquals("ABCDEF", getUniqueCharacterSubstring("ABCDEFF"));
    assertEquals("NGISAWE", getUniqueCharacterSubstring("CODINGISAWESOME"));
    assertEquals("be coding", getUniqueCharacterSubstring("always be coding"));
}

Ici, nous essayons ettest boundary conditions as well as the more typical use cases.

5. Conclusion

Dans ce didacticiel, nous avons appris à utiliser la technique de la fenêtre coulissante pour trouver la sous-chaîne la plus longue avec des caractères non répétitifs.

Et, comme toujours, le code source est disponibleover on GitHub.