Je ne sais pas comment un bit vecteur fonctionnerait pour faire cela (pas trop familier avec les vecteurs bit). Voici le code donné. Quelqu'un pourrait-il s'il vous plaît me guider à travers cela?
public static boolean isUniqueChars(String str) {
int checker = 0;
for (int i = 0; i < str.length(); ++i) {
int val = str.charAt(i) - 'a';
if ((checker & (1 << val)) > 0) return false;
checker |= (1 << val);
}
return true;
}
En particulier, que checker
fait-on?
java
string
bit-manipulation
bitvector
user1136342
la source
la source
Réponses:
int checker
est utilisé ici comme stockage des bits. Chaque bit dans une valeur entière peut être traité comme un drapeau, donc finalementint
un tableau de bits (drapeau). Chaque bit de votre code indique si le caractère avec l'index de bit a été trouvé dans la chaîne ou non. Vous pouvez utiliser le vecteur de bits pour la même raison au lieu deint
. Il existe deux différences entre eux:Taille .
int
a une taille fixe, généralement 4 octets, ce qui signifie 8 * 4 = 32 bits (drapeaux). Le vecteur de bits peut généralement être de taille différente ou vous devez spécifier la taille dans le constructeur.API . Avec les vecteurs de bits, vous aurez un code plus facile à lire, probablement quelque chose comme ceci:
vector.SetFlag(4, true); // set flag at index 4 as true
car
int
vous aurez un code logique de bit de niveau inférieur:checker |= (1 << 5); // set flag at index 5 to true
int
Peut-être aussi probablement un peu plus rapide, car les opérations avec des bits sont de très bas niveau et peuvent être exécutées telles quelles par le processeur. BitVector permet à la place d'écrire un peu moins de code cryptique et de stocker plus d'indicateurs.Pour référence future: le vecteur de bits est également appelé bitSet ou bitArray. Voici quelques liens vers cette structure de données pour différentes langues / plates-formes:
la source
J'ai un soupçon furtif que vous ayez obtenu ce code du même livre que je lis ... Le code lui-même n'est pas aussi cryptique que les opérateurs- | =, &, et << qui ne sont normalement pas utilisés par nous profanes - l'auteur n'a pas pris la peine de prendre le temps supplémentaire d'expliquer le processus ni la mécanique réelle impliquée ici. J'étais content de la réponse précédente sur ce fil au début, mais uniquement à un niveau abstrait. J'y suis revenu parce que je sentais qu'il fallait une explication plus concrète - l'absence d'une explication me laisse toujours un sentiment de malaise.
Cet opérateur << est un décalage de bits à gauche, il prend la représentation binaire de ce nombre ou de l'opérande et le décale sur le nombre de places spécifié par l'opérande ou le nombre à droite comme en nombres décimaux uniquement dans les binaires. Nous multiplions par la base 2 - lorsque nous progressons, quel que soit le nombre de places pas la base 10 - donc le nombre de droite est l'exposant et le nombre de gauche est un multiple de base de 2.
Cet opérateur | = prend l'opérande à gauche et ou est avec l'opérande à droite - et celui-ci - '&' et est les bits des deux opérandes à gauche et à droite de celui-ci.
Donc, ce que nous avons ici est une table de hachage qui est stockée dans un nombre binaire de 32 bits chaque fois que le vérificateur obtient ou'd (
checker |= (1 << val)
) avec la valeur binaire désignée d'une lettre, son bit correspondant est mis à true. La valeur du personnage est et avec le vérificateur (checker & (1 << val)) > 0
) - si elle est supérieure à 0, nous savons que nous avons une dupe - parce que deux bits identiques mis à vrai et ensemble renverront vrai ou '1' '.Il y a 26 emplacements binaires dont chacun correspond à une lettre minuscule - l'auteur a dit de supposer que la chaîne ne contient que des lettres minuscules - et c'est parce qu'il ne nous reste plus que 6 emplacements (en entier de 32 bits) à consommer - et que nous avoir une collision
Donc, pour une chaîne d'entrée 'azya', comme on se déplace pas à pas
chaîne 'a'
chaîne 'az'
chaîne 'azy'
chaîne 'azya'
Maintenant, il déclare un doublon
la source
Je pense que toutes ces réponses expliquent comment cela fonctionne, mais j'avais envie de donner mon avis sur la façon dont je le voyais mieux, en renommant certaines variables, en en ajoutant d'autres et en y ajoutant des commentaires:
la source
Je suppose également que votre exemple provient du livre Cracking The Code Interview et ma réponse est liée à ce contexte.
Afin d'utiliser cet algorithme pour résoudre le problème, nous devons admettre que nous n'allons passer que des caractères de a à z (minuscules).
Comme il n'y a que 26 lettres et que celles-ci sont correctement triées dans la table de codage que nous utilisons, cela nous garantit que toutes les différences potentielles
str.charAt(i) - 'a'
seront inférieures à 32 (la taille de la variable intchecker
).Comme expliqué par Snowbear, nous sommes sur le point d'utiliser la
checker
variable comme un tableau de bits. Permet d'avoir une approche par exemple:Disons
str equals "test"
et ainsi de suite .. jusqu'à ce que nous trouvions un bit déjà défini dans le vérificateur pour un caractère spécifique via la condition
J'espère que ça aide
la source
Il y a quelques excellentes réponses déjà fournies ci-dessus. Je ne veux donc pas répéter ce que tout a déjà dit. Mais je voulais ajouter quelques éléments pour aider avec le programme ci-dessus car je viens de travailler avec le même programme et j'avais quelques questions, mais après avoir passé un certain temps, j'ai plus de clarté sur ce programme.
Tout d'abord, "checker" est utilisé pour suivre le caractère déjà traversé dans la chaîne afin de voir s'il y a des caractères qui se répètent.
Désormais, "checker" est un type de données int, il ne peut donc avoir que 32 bits ou 4 octets (selon la plate-forme), ce programme ne peut donc fonctionner correctement que pour un jeu de caractères compris dans une plage de 32 caractères. C'est la raison pour laquelle ce programme soustrait «a» de chaque caractère afin de faire fonctionner ce programme uniquement pour les caractères minuscules. Cependant, si vous mélangez des caractères minuscules et majuscules, cela ne fonctionnera pas.
En passant, si vous ne soustrayez pas «a» de chaque caractère (voir l'instruction ci-dessous), ce programme fonctionnera correctement pour uniquement String avec des caractères majuscules ou String avec uniquement des caractères minuscules. Ainsi, la portée du programme ci-dessus augmente des caractères minuscules aux caractères majuscules, mais ils ne peuvent pas être mélangés ensemble.
Cependant, je voulais écrire un programme générique utilisant l'opération au niveau du bit qui devrait fonctionner pour tous les caractères ASCII sans se soucier des majuscules, des minuscules, des nombres ou de tout caractère spécial. Pour ce faire, notre "vérificateur" doit être suffisamment grand pour stocker 256 caractères (taille du jeu de caractères ASCII). Mais un int en Java ne fonctionnerait pas car il ne peut stocker que 32 bits. Par conséquent, dans le programme ci-dessous, j'utilise la classe BitSet disponible dans JDK qui peut avoir n'importe quelle taille définie par l'utilisateur lors de l'instanciation d'un objet BitSet.
Voici un programme qui fait la même chose que le programme ci-dessus écrit en utilisant l'opérateur Bitwise mais ce programme fonctionnera pour une chaîne avec n'importe quel caractère du jeu de caractères ASCII.
la source
for(int i = 0; i < s.length(); i++) { int charVal = s.charAt(i); if(tracker.get(charVal)) { return false; } tracker.set(charVal); }
La lecture de la réponse d'Ivan ci-dessus m'a vraiment aidé, même si je la formulerais un peu différemment.
L'
<<
en(1 << val)
est un opérateur de décalage de bit. Il prend1
(qui en binaire est représenté par000000001
, avec autant de zéros précédents que vous le souhaitez / sont alloués par la mémoire) et le décale vers la gauche par desval
espaces. Puisque nous supposons az uniquement et soustrayons àa
chaque fois, chaque lettre aura une valeur de 0-25, qui sera l'index de cette lettre à partir de la droite dans lachecker
représentation booléenne de l' entier, puisque nous déplacerons le1
vers la gauche danschecker
val
temps.À la fin de chaque contrôle, nous voyons l'
|=
opérateur. Ceci fusionne deux nombres binaires, en remplaçant tous0
les s par1
s si un1
existe dans l'un ou l'autre des opérandes à cet index. Ici, cela signifie que partout où un1
existe(1 << val)
,1
il sera copiéchecker
, tandis que touschecker
les 1 existants seront préservés.Comme vous pouvez probablement le deviner, a
1
fonctionne ici comme un indicateur booléen pour true. Lorsque nous vérifions si un caractère est déjà représenté dans la chaîne, nous comparonschecker
, qui à ce stade est essentiellement un tableau de drapeaux booléens (1
valeurs) aux index de caractères déjà représentés, avec ce qui est essentiellement un tableau de valeurs booléennes avec un1
indicateur à l'index du caractère courant.L'
&
opérateur effectue ce contrôle. Similaire à|=
, l'&
opérateur ne copiera sur a1
que si les deux opérandes ont un1
à cet index. Donc, essentiellement, seuls les drapeaux déjà présents danschecker
qui sont également représentés dans(1 << val)
seront copiés. Dans ce cas, cela signifie que si le caractère courant a déjà été représenté, il y aura un1
cadeau n'importe où dans le résultat dechecker & (1 << val)
. Et si a1
est présent n'importe où dans le résultat de cette opération, alors la valeur du booléen retourné est> 0
, et la méthode renvoie false.C'est, je suppose, pourquoi les vecteurs de bits sont également appelés tableaux de bits . Parce que, même s'ils ne sont pas du type de données tableau, ils peuvent être utilisés de la même manière que les tableaux sont utilisés pour stocker des indicateurs booléens.
la source
Explication simple (avec le code JS ci-dessous)
32-bit
DEC64
pour JS.0th
index si nous trouvonsa
dans la chaîne,1st
pourb
etc.Résumé des opérations:
checker
&index
du caractèreInt-32-Arrays
if
la sortie de l'opération était1
output == 1
checker
variable a ce bit d'index-ième particulier défini dans les deux tableauxoutput == 0
checker
&index
du caractère1
checker
Hypothèses:
a
is97
Vous trouverez ci-dessous le code source JavaScript .
Notez que dans JS, bien que les entiers soient de 64 bits, une opération par bit est toujours effectuée sur 32 bits.
Exemple: Si la chaîne est
aa
alors:i = 0
i = 1
la source
Permet de décomposer le code ligne par ligne.
vérificateur int = 0; Nous lançons un vérificateur qui nous aidera à trouver les valeurs en double.
int val = str.charAt (i) - 'a'; Nous obtenons la valeur ASCII du caractère à la «i» position de la chaîne et la soustrayons avec la valeur ASCII de «a». Puisque l'hypothèse est que la chaîne est composée uniquement de caractères inférieurs, le nombre de caractères est limité à 26. Hece, la valeur de «val» sera toujours> = 0.
if ((checker & (1 << val))> 0) return false;
vérificateur | = (1 << val);
Maintenant, c'est la partie délicate. Prenons un exemple avec la chaîne "abcda". Cela devrait idéalement renvoyer false.
Pour l'itération de boucle 1:
Vérificateur: 00000000000000000000000000000000
val: 97-97 = 0
1 << 0: 00000000000000000000000000000001
checker & (1 << val): 00000000000000000000000000000000 n'est pas> 0
D'où le vérificateur: 00000000000000000000000000000001
Pour l'itération de boucle 2:
Vérificateur: 00000000000000000000000000000001
val: 98-97 = 1
1 << 0: 00000000000000000000000000000010
checker & (1 << val): 00000000000000000000000000000000 n'est pas> 0
D'où le vérificateur: 00000000000000000000000000000011
Pour l'itération de boucle 3:
Vérificateur: 00000000000000000000000000000011
val: 99-97 = 0
1 << 0: 00000000000000000000000000000100
checker & (1 << val): 00000000000000000000000000000000 n'est pas> 0
D'où le vérificateur: 00000000000000000000000000000111
Pour l'itération de boucle 4:
Vérificateur: 00000000000000000000000000000111
val: 100-97 = 0
1 << 0: 00000000000000000000000000001000
checker & (1 << val): 00000000000000000000000000000000 n'est pas> 0
D'où le vérificateur: 00000000000000000000000000001111
Pour l'itération de boucle 5:
Vérificateur: 00000000000000000000000000001111
val: 97-97 = 0
1 << 0: 00000000000000000000000000000001
checker & (1 << val): 00000000000000000000000000000001 est> 0
Par conséquent, retournez false.
la source
la source
Les articles précédents expliquent bien ce que fait le bloc de code et je veux ajouter ma solution simple en utilisant la structure de données BitSet java:
la source
La façon dont j'ai compris l'utilisation de Javascript. En supposant une entrée
var inputChar = "abca"; //find if inputChar has all unique characters
Commençons
Line 4: int val = str.charAt(i) - 'a';
En Javascript Ex:
"a".charCodeAt().toString(2)
renvoie 1100001checker = 1100001 | checker;
// le vérificateur devient 1100001 (dans la représentation 32 bits, il devient 000000000 ..... 00001100001)Mais je veux que mon masque de bits (
int checker
) ne définisse qu'un bit, mais le vérificateur est 1100001Permet d'utiliser
val
ce qui est réinitialiséLa ligne 5 et la ligne 6 sont bien expliquées @Ivan answer
la source
Juste au cas où quelqu'un recherche l'équivalent kotlin de caractères uniques dans une chaîne en utilisant un vecteur de bits
Réf: https://www.programiz.com/kotlin-programming/bitwise
la source