5
votes

Rechercher la plus grande sous-chaîne contenant un nombre égal de 0 et de 1 dans une chaîne binaire

Récemment, lors d'une interview, on m'a demandé d'écrire un programme pour trouver la plus grande sous-chaîne contenant un nombre égal de 0 et de 1 dans une chaîne binaire.

/ p>

Par exemple:

Si la chaîne donnée est 1010111 alors la sortie sera 1010 car elle contient 2 0 s et 2 1 s.

J'ai beaucoup essayé mais je ne parviens pas à créer un algorithme pour cette chose.

Quelqu'un peut-il me donner une longueur d'avance sur la façon de procéder ou sur la structure de données à utiliser pour ce problème?


10 commentaires

cela vous aiderait si vous considérez 0 valeurs comme -1? réduire le problème à trouver la longueur maximale du tableau avec une somme de 0?


Le 0101 (commençant par le premier 0) ne fonctionnerait-il pas également? Ou est-ce le premier trouvé?


@SamerTufail Je pense que ce problème peut être remplacé en considérant 2 nombres ou même des caractères, donc je pense que trouver une somme de 0 n'est pas correct


@ M.K puisque le point principal est de trouver le plus long, donc je pense que 0101 peut aussi être considéré


@VivekMishra s'il s'agit de deux nombres ou de deux caractères quelconques, vous pouvez également le mapper à -1 et 1. Comment pouvez-vous réfuter que trouver une somme de 0 n'est pas correct?


@SamerTufail désolé n'a pas compris le contexte complet. Si vous parlez de mappage de contexte, cela peut fonctionner


que devrait être o / p pour: 00001111?


@SJC dans ce cas, la chaîne entière sera la sortie


Ceci est un exemple courant de langages sans contexte. Avec une bande de sortie supplémentaire, vous pouvez le faire en $ O (n) $. Construisez une pile, lorsque vous voyez $ 1 $ ou $ 0 $ (l'un d'eux, continuez à pousser ce symbole sur la pile, lorsque vous voyez l'opposé de cela, continuez à supprimer le symbole). La plus grande chaîne sera la taille initiale de la pile (lorsque vous avez fini d'appuyer sur le premier symbole) moins la taille de la pile à la fin.


Une recherche sur Internet vous aurait aidé à trouver des algorithmes et des implémentations. J'en ai trouvé un ici par exemple: geeksforgeeks. org /…


3 Réponses :


11
votes

Ce qui suit fonctionnera dans le temps et l'espace O (n) , n étant le nombre de caractères de la chaîne.

  • garder une trace du solde actuel (ou du déséquilibre) de 1 et 0 que vous avez vu dans la chaîne code> et la première fois où la chaîne a le même solde (un tableau ou une carte avec au plus n entrées)
  • itérer la chaîne , et pour chaque caractère ...
    • mettre à jour le solde , en comptant "1" comme 1 et "0" comme - 1 ou vice versa
    • vérifier quand, le cas échéant, vous avez rencontré le même solde avant
    • si la différence est supérieure au meilleur actuel, souvenez-vous de la nouvelle sous-chaîne la plus longue
    • si vous n'avez pas encore rencontré ce solde, rappelez-vous qu'il s'agit de la première position actuelle

Exemple de code en Python:

0 1 1  {0: 0, 1: 1}
1 0 0 10 {0: 0, 1: 1}
2 1 1 10 {0: 0, 1: 1}
3 0 0 1010 {0: 0, 1: 1}
4 1 1 1010 {0: 0, 1: 1}
5 1 2 1010 {0: 0, 1: 1, 2: 6}
6 1 3 1010 {0: 0, 1: 1, 2: 6, 3: 7}
7 0 2 1010 {0: 0, 1: 1, 2: 6, 3: 7}
8 0 1 01011100 {0: 0, 1: 1, 2: 6, 3: 7}
9 0 0 1010111000 {0: 0, 1: 1, 2: 6, 3: 7}

Sortie:

string = "1010111000"
first = {0: 0}  # map or array; 0th element is 0
balance = 0     # initially, 1 and 0 are balanced
best = ""       # best substring found
for i, c in enumerate(string):             # (i, c) = (index, character)
    balance += 1 if c == "1" else -1       # update balance
    if balance not in first:               # first time we see this balance?
        first[balance] = i+1               # add next(!) position to map/array
    elif i - first[balance] > len(best):   # otherwise, if new longest substring
        best = string[first[balance]:i+1]  # update best with slice of string
    print(i, c, balance, best, first)      # debugging/demo output


10 commentaires

Par déséquilibre, voulez-vous dire garder le nombre de 0 et 1 dans un tableau / dictionnaire? Ou différence entre le nombre


balance + = 1 if c == "1" else -1 à peu près ce que j'avais indiqué dans le premier commentaire, le problème s'est maintenant réduit à trouver le sous-tableau maximum avec sum = 0


@SamerTufail Oui, je suppose que nous avons eu la même idée ici. Ce n'était pas tout à fait clair dans votre commentaire, en particulier que vous ne pouvez pas simplement considérer toutes les positions où sum = 0 mais toutes où c'est la même chose que n'importe quelle valeur précédente.


vous ne pouvez pas simplement considérer toutes les positions où somme = 0 - Pourquoi pas? si c'est 0 alors cela signifie que la valeur de sum est sum-1 où la somme commence à 0 et toutes les positions avec sum = 0 sont des réponses potentielles.


@SamerTufail Ce n'était peut-être pas tout à fait clair. Je voulais dire que vous ne pouvez pas simplement considérer les endroits où (dans mon code) le "solde" est nul, car ce ne serait que les sous-chaînes commençant au premier index. Vous avez également besoin d'une liste / carte des premières positions d'autres soldes ou sommes, comme vous l'avez également dans votre algorithme.


Ah, d'accord désolé oui, j'ai mal compris. :)


@tobias_k Je ne suis pas familier avec python, donc je veux demander si c représente le caractère de la chaîne? Et first est un tableau?


@VivekMishra Exactement, i est la position actuelle et c le caractère. first est une carte / dictionnaire / tableau associatif, mais vous pouvez également utiliser un tableau régulier ou une liste de taille n , avec tous les éléments initialisés comme par ex. -1 sauf le 0 qui doit être 0 .


Pouvez-vous également expliquer ce que fait cette ligne? best = string [premier [solde]: i + 1] .


@VivekMishra Cela récupère la sous-chaîne à partir de la position stockée dans la première carte / tableau jusqu'à et y compris la position actuelle. J'ai ajouté des commentaires à chaque ligne. J'espère que cela clarifie les choses.



4
votes

Je l'aborderais comme ça

  • Initialise une somme entière variable et maxlength = minimum

  • Définissez un hashmap avec avec sum comme clé et index comme valeur

  • Pour chaque valeur de la chaîne donnée

    • somme + = arr [i] == 0? puis ajoutez -1 sinon ajoutez un 1

    • si la somme est 0 maxlength = maxlength ou index + 1 puisqu'il s'agit d'une réponse potentielle

    • sinon si le dictionnaire contient cette valeur de somme, maxlength = maxlength ou (i -index hash [sum]) la valeur de la somme trouvée précédemment contribuant au résultat.

    • met à jour la table de hachage si la valeur de sum n'est pas dans la carte de hachage avec index

    • renvoie la longueur maximale.

Voici un exemple de ce que j'ai mentionné ci-dessus, dans le code: exemple fonctionnel vous pouvez essayer de changer le cas de test pour voir comment cela fonctionnerait pour différents cas de test, essayez également d'imprimer la carte de hachage et de la tracer à la main pour mieux comprendre.


0 commentaires

2
votes

Cette solution n'est pas la meilleure en termes d'optimisation, mais dans la précipitation et le stress d'une interview, celle-ci peut être rapidement pensée, dessinée et expliquée.

Je nicherais 2 boucles. p >

1 de 0 à len - 2 (incrémentation) (la longueur minimale doit être de 2)

1 à partir de len à la valeur de boucle précédente + 2 (décrémentation) (la longueur minimale doit être de 2 )

Récupère la sous-chaîne des itérateurs correspondants des boucles

Compter si les caractères sont égaux.

alors, si vrai, comparer avec la longueur du résultat stocké, si la longueur est supérieure, écrasez le résultat.

En utilisant 0100 comme exemple, cela testera par rapport à ces valeurs:

var iterations = 0;

function IsBalanced(input, char1, char2)
{
    if (input.length % 2 != 0) // odd length can't be balanced
    {
      ++iterations;
      return (false);
    }
    let char1count = 0;
    let char2count = 0;
    let len = input.length;
    for (let i = 0; i < len; ++i)
    {
        ++iterations;
        if (input[i] == char1)
            ++char1count;
        else
            ++char2count;
    }
    return (char1count == char2count);
}

function findLargest(input, char1, char2)
{
    let len = input.length;
    let result = '';
    for (let k = 0; k < len - 1; ++k)
    {
        //        This is a tweak to reduce the number of iterations
        //  To avoid testing a substring smaller than the current result
        //                           |
        //                           |
        //                v----------------------v
        for (let l = len; l - k > result.length && l > k + 1; --l)
        {
            tempResult = input.substring(k, l);
            if (IsBalanced(tempResult, char1, char2) && tempResult.length > result.length)
                result = tempResult;
        }
    }
    return (result);
}

console.log("Input : 1010111 - result : " + findLargest("1010111", "1", "0") + " original size : " + "1010111".length + " - iterations : " + iterations);
iterations = 0;
console.log("Input : ababaaa - result : " + findLargest("ababaaa", "a", "b") + " original size : " + "ababaaa".length + " - iterations : " + iterations);
iterations = 0;
console.log("Input : 00100100 - result : " + findLargest("00100100", "1", "0") + " original size : " + "00100100".length + " - iterations : " + iterations);
iterations = 0;
console.log("Input : 1111100000 - result : " + findLargest("1111100000", "1", "0") + " original size : " + "1111100000".length + " - iterations : " + iterations);
iterations = 0;
console.log("Input : 0001111111111010001111100000000001111111111 - result : " + findLargest("0001111111111010001111100000000001111111111", "1", "0") + " original size : " + "0001111111111010001111100000000001111111111".length + " - iterations : " + iterations);
iterations = 0;
console.log("Input : 0000000000000000000000000000000000000000000000000001 - result : " + findLargest("0000000000000000000000000000000000000000000000000001", "1", "0") + " original size : " + "0000000000000000000000000000000000000000000000000001".length + " - iterations : " + iterations);

Exemple JavaScript (je l'ai un peu modifié pour optimiser le nombre d'itérations, mais l'approche est la même):

// result = ''
0100 //not balanced
010  //not balanced
01   //balanced AND length is greated than result's one. result = '01'
 100 //not balanced
 10  //balanced BUT length is not greated than result's one
  00 //not balanced


0 commentaires