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 code> 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?
3 Réponses :
Ce qui suit fonctionnera dans le temps et l'espace O (n) , n étant le nombre de caractères de la chaîne.
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)
chaîne
, et pour chaque caractère ...
solde
, en comptant "1"
comme 1
et "0"
comme - 1
ou vice versa solde
avant meilleur
actuel, souvenez-vous de la nouvelle sous-chaîne la plus longue 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
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.
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.
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
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 /…