Leg het gebruik van een bitvector uit om te bepalen of alle karakters uniek zijn

Ik ben in de war over hoe een bitvector zou werken om dit te doen (niet zo bekend met bitvectoren). Hier is de gegeven code. Kan iemand me hier doorheen leiden?

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;
}

In het bijzonder, wat doet de checker?


Antwoord 1, autoriteit 100%

int checkerwordt hier gebruikt als opslag voor bits. Elke bit in integerwaarde kan worden behandeld als een vlag, dus uiteindelijk is inteen array van bits (vlag). Elk bit in uw code geeft aan of het teken met de bitindex in string is gevonden of niet. Je zou om dezelfde reden bitvector kunnen gebruiken in plaats van int. Er zijn twee verschillen tussen hen:

  • Maat. intheeft een vaste grootte, meestal 4 bytes, wat 8*4=32 bits (vlaggen) betekent. Bitvector kan meestal een verschillende grootte hebben of u moet de grootte specificeren in de constructor.

  • API. Met bitvectoren heb je gemakkelijker te lezen code, waarschijnlijk zoiets als dit:

    vector.SetFlag(4, true); // set flag at index 4 as true

    voor intheb je een lagere bitlogica-code:

    checker |= (1 << 5); // set flag at index 5 to true

Waarschijnlijk is ook intmisschien een beetje sneller, omdat bewerkingen met bits erg laag zijn en door de CPU kunnen worden uitgevoerd zoals ze zijn. Met BitVector kan in plaats daarvan een beetje minder cryptische code worden geschreven, plus het kan meer vlaggen opslaan.

Voor toekomstig gebruik: bitvector is ook bekend als bitSet of bitArray. Hier zijn enkele links naar deze gegevensstructuur voor verschillende talen/platforms:


Antwoord 2, autoriteit 91%

Ik heb een heimelijk vermoeden dat je deze code uit hetzelfde boek hebt gehaald als ik aan het lezen ben… De code zelf is hier lang niet zo cryptisch als de operators- |=, &, en << die normaal niet door ons leken worden gebruikt – de auteur nam niet de moeite om de extra tijd te nemen om het proces uit te leggen, noch wat de eigenlijke mechanica hier is. Ik was in het begin tevreden met het vorige antwoord op deze draad, maar alleen op een abstract niveau. Ik kwam erop terug omdat ik vond dat er een meer concrete verklaring moest zijn – het ontbreken ervan geeft me altijd een ongemakkelijk gevoel.

deze operator & lt; & lt; Is een linkse bitwise-shifter het kost de binaire weergave van dat nummer of operand en verschuift het echter op veel plaatsen die zijn opgegeven door de operand of het nummer aan de rechterkant zoals in decimale nummers alleen in binaries. We vermenigvuldigen zich met basis 2 – wanneer we echter opdagen, veel plaatsen niet base 10-, dus het nummer aan de rechterkant is de exponent en het nummer aan de linkerkant is een basis meervoudig van 2.

Deze operator | = Neem de operand aan de linkerkant en of is het met de operand aan de rechter- en deze ‘& amp;’ en zijn de stukjes van beide operanden naar links en rechts daarvan.

Dus wat we hier hebben is een hash-tabel die wordt opgeslagen in een 32-bits binair nummer telkens wanneer de checker krijgt of (checker |= (1 << val)) Met de aangewezen binaire waarde van een letter is het bijbehorende bit waarop het is ingesteld op TRUE.
De waarde van het personage is en had met de checker (checker & (1 << val)) > 0) – Als het groter is dan 0, weten we dat we een dupe hebben – omdat twee identieke bits op true zijn en samen true of ‘1’ zullen terugkeren.

Er zijn 26 binaire plaatsen die elk overeenkomen met een kleine letter – de auteur heeft gezegd dat de reeks alleen kleine letters bevat – en dit is omdat we slechts 6 meer hebben (in 32-bits integer) plaatsen om te consumeren en dan krijgen we een botsing

00000000000000000000000000000001 a 2^0
00000000000000000000000000000010 b 2^1
00000000000000000000000000000100 c 2^2
00000000000000000000000000001000 d 2^3
00000000000000000000000000010000 e 2^4
00000000000000000000000000100000 f 2^5
00000000000000000000000001000000 g 2^6
00000000000000000000000010000000 h 2^7
00000000000000000000000100000000 i 2^8
00000000000000000000001000000000 j 2^9
00000000000000000000010000000000 k 2^10
00000000000000000000100000000000 l 2^11
00000000000000000001000000000000 m 2^12
00000000000000000010000000000000 n 2^13
00000000000000000100000000000000 o 2^14
00000000000000001000000000000000 p 2^15
00000000000000010000000000000000 q 2^16
00000000000000100000000000000000 r 2^17
00000000000001000000000000000000 s 2^18
00000000000010000000000000000000 t 2^19
00000000000100000000000000000000 u 2^20
00000000001000000000000000000000 v 2^21
00000000010000000000000000000000 w 2^22
00000000100000000000000000000000 x 2^23
00000001000000000000000000000000 y 2^24
00000010000000000000000000000000 z 2^25

Dus, voor een invoerreeks ‘azya’, zoals we stap voor stap gaan

string ‘a’

a      =00000000000000000000000000000001
checker=00000000000000000000000000000000
checker='a' or checker;
// checker now becomes = 00000000000000000000000000000001
checker=00000000000000000000000000000001
a and checker=0 no dupes condition

string ‘az’

checker=00000000000000000000000000000001
z      =00000010000000000000000000000000
z and checker=0 no dupes 
checker=z or checker;
// checker now becomes 00000010000000000000000000000001  

string ‘azy’

checker= 00000010000000000000000000000001    
y      = 00000001000000000000000000000000 
checker and y=0 no dupes condition 
checker= checker or y;
// checker now becomes = 00000011000000000000000000000001

string ‘azya’

checker= 00000011000000000000000000000001
a      = 00000000000000000000000000000001
a and checker=1 we have a dupe

Nu declareert het een duplicaat


Antwoord 3, autoriteit 57%

Ik denk dat al deze antwoorden verklaren hoe dit werkt, maar ik had zin om mijn input te geven over hoe ik het beter zag, door enkele variabelen te hernoemen, andere toe te voegen en er opmerkingen aan toe te voegen:

public static boolean isUniqueChars(String str) {
    /*
    checker is the bit array, it will have a 1 on the character index that
    has appeared before and a 0 if the character has not appeared, you
    can see this number initialized as 32 0 bits:
    00000000 00000000 00000000 00000000
     */
    int checker = 0;
    //loop through each String character
    for (int i = 0; i < str.length(); ++i) {
        /*
        a through z in ASCII are charactets numbered 97 through 122, 26 characters total
        with this, you get a number between 0 and 25 to represent each character index
        0 for 'a' and 25 for 'z'
        renamed 'val' as 'characterIndex' to be more descriptive
         */
        int characterIndex = str.charAt(i) - 'a'; //char 'a' would get 0 and char 'z' would get 26
        /*
        created a new variable to make things clearer 'singleBitOnPosition'
        It is used to calculate a number that represents the bit value of having that 
        character index as a 1 and the rest as a 0, this is achieved
        by getting the single digit 1 and shifting it to the left as many
        times as the character index requires
        e.g. character 'd'
        00000000 00000000 00000000 00000001
        Shift 3 spaces to the left (<<) because 'd' index is number 3
        1 shift: 00000000 00000000 00000000 00000010
        2 shift: 00000000 00000000 00000000 00000100
        3 shift: 00000000 00000000 00000000 00001000
        Therefore the number representing 'd' is
        00000000 00000000 00000000 00001000
         */
        int singleBitOnPosition = 1 << characterIndex;
        /*
        This peforms an AND between the checker, which is the bit array
        containing everything that has been found before and the number
        representing the bit that will be turned on for this particular
        character. e.g.
        if we have already seen 'a', 'b' and 'd', checker will have:
        checker = 00000000 00000000 00000000 00001011
        And if we see 'b' again:
        'b' = 00000000 00000000 00000000 00000010
        it will do the following:
        00000000 00000000 00000000 00001011
        & (AND)
        00000000 00000000 00000000 00000010
        -----------------------------------
        00000000 00000000 00000000 00000010
        Since this number is different than '0' it means that the character
        was seen before, because on that character index we already have a 
        1 bit value
         */
        if ((checker & singleBitOnPosition) > 0) {
            return false;
        }
        /* 
        Remember that 
        checker |= singleBitOnPosition is the same as  
        checker = checker | singleBitOnPosition
        Sometimes it is easier to see it expanded like that.
        What this achieves is that it builds the checker to have the new 
        value it hasnt seen, by doing an OR between checker and the value 
        representing this character index as a 1. e.g.
        If the character is 'f' and the checker has seen 'g' and 'a', the 
        following will happen
        'f' = 00000000 00000000 00000000 00100000
        checker(seen 'a' and 'g' so far) = 00000000 00000000 00000000 01000001
        00000000 00000000 00000000 00100000
        | (OR)
        00000000 00000000 00000000 01000001
        -----------------------------------
        00000000 00000000 00000000 01100001
        Therefore getting a new checker as 00000000 00000000 00000000 01100001
         */
        checker |= singleBitOnPosition;
    }
    return true;
}

Antwoord 4, autoriteit 7%

Het lezen van Ivan’s antwoord hierboven heeft me echt geholpen, hoewel ik het iets anders zou formuleren.

De <<in (1 << val)is een bitverschuivende operator. Het duurt 1(wat in binair getal wordt weergegeven als 000000001, met zoveel voorafgaande nullen als je wilt / wordt toegewezen door het geheugen) en verschuift het naar links met valspaties. Aangezien we alleen az aannemen en elke keer aaftrekken, heeft elke letter een waarde van 0-25, wat de index van die letter van rechts in de checkerzal zijn integer’s booleaanse representatie, aangezien we de 1naar links zullen verplaatsen in checkervalkeer.

Aan het einde van elke controle zien we de operator |=. Dit voegt twee binaire getallen samen, waarbij alle 0‘s worden vervangen door 1‘en als er een 1bestaat in een van beide operands op die index. Hier betekent dat dat overal waar een 1bestaat in (1 << val), die 1zal worden gekopieerd naar checker, terwijl alle bestaande enen van checkerbehouden blijven.

Zoals je waarschijnlijk wel kunt raden, functioneert een 1hier als een booleaanse vlag voor waar. Als we controleren of een teken al in de tekenreeks voorkomt, vergelijken we checker, wat op dit moment in wezen een reeks booleaanse vlaggen (1-waarden) is aan de indexen van tekens die al zijn weergegeven, met in wezen een array van booleaanse waarden met een 1-vlag bij de index van het huidige teken.

De operator &voert deze controle uit. Net als bij de |=, kopieert de operator &een 1alleenals beide operanden een 1bij die index. Dus in wezen worden alleen vlaggen die al aanwezig zijn in checkeren die ook worden weergegeven in (1 << val)gekopieerd. In dit geval betekent dat alleen als het huidige teken al is weergegeven, er een 1aanwezig zal zijn ergens in het resultaat van checker & (1 << val). En als een 1ergens in het resultaat van die bewerking aanwezig is, dan is de waarde van de geretourneerde boolean > 0, en de methode retourneert false.

Dit is, vermoed ik, waarom bitvectoren ook bit-arraysworden genoemd. Omdat, hoewel ze niet van het gegevenstype array zijn, ze kunnen worden gebruikt op dezelfde manier als arrays worden gebruikt om booleaanse vlaggen op te slaan.


Antwoord 5, autoriteit 6%

Er zijn hierboven al een paar uitstekende antwoorden gegeven. Dus ik wil niet herhalen wat alles al is gezegd. Maar ik wilde een paar dingen toevoegen om te helpen met het bovenstaande programma, omdat ik net hetzelfde programma heb doorlopen en een paar vragen had, maar na wat tijd te hebben doorgebracht, heb ik meer duidelijkheid over dit programma.

Allereerst wordt “checker” gebruikt om het teken te volgen dat al in de tekenreeks is doorlopen om te zien of er tekens worden herhaald.

Nu is “checker” een int-gegevenstype, dus het kan slechts 32 bits of 4 bytes hebben (afhankelijk van het platform), dus dit programma kan alleen correct werken voor een tekenset binnen een bereik van 32 tekens. Dat is de reden dat dit programma ‘a’ van elk teken aftrekt om dit programma alleen voor kleine letters te laten werken. Als u echter kleine letters en hoofdletters door elkaar gebruikt, werkt het niet.

Trouwens, als u ‘a’ niet van elk teken aftrekt (zie onderstaande verklaring), dan werkt dit programma alleen correct voor String met hoofdletters of String met alleen kleine letters. Dus de reikwijdte van het bovenstaande programma neemt toe van alleen kleine letters naar hoofdletters, maar ze kunnen niet met elkaar worden gemengd.

int val = str.charAt(i) - 'a'; 

Ik wilde echter een generiek programma schrijven met Bitwise Operation dat zou moeten werken voor alle ASCII-tekens zonder me zorgen te maken over hoofdletters, kleine letters, cijfers of een speciaal teken. Om dit te doen, moet onze “checker” groot genoeg zijn om 256 tekens op te slaan (ASCII-tekensetgrootte). Maar een int in Java zou niet werken omdat het maar 32 bits kan opslaan. Daarom gebruik ik in het onderstaande programma de BitSet-klasse die beschikbaar is in JDK, waaraan elke door de gebruiker gedefinieerde grootte kan worden doorgegeven tijdens het instantiëren van een BitSet-object.

Hier is een programma dat hetzelfde doet als bovenstaand programma, geschreven met de Bitwise-operator, maar dit programma werkt voor een string met elk willekeurig teken uit de ASCII-tekenset.

public static boolean isUniqueStringUsingBitVectorClass(String s) {
    final int ASCII_CHARACTER_SET_SIZE = 256;
    final BitSet tracker = new BitSet(ASCII_CHARACTER_SET_SIZE);
    // if more than  256 ASCII characters then there can't be unique characters
    if(s.length() > 256) {
        return false;
    }
    //this will be used to keep the location of each character in String
    final BitSet charBitLocation = new BitSet(ASCII_CHARACTER_SET_SIZE);
    for(int i = 0; i < s.length(); i++) {
        int charVal = s.charAt(i);
        charBitLocation.set(charVal); //set the char location in BitSet
        //check if tracker has already bit set with the bit present in charBitLocation
        if(tracker.intersects(charBitLocation)) {
            return false;
        }
        //set the tracker with new bit from charBitLocation
        tracker.or(charBitLocation);
        charBitLocation.clear(); //clear charBitLocation to store bit for character in the next iteration of the loop
    }
    return true;
}

Antwoord 6, autoriteit 3%

Laten we de code regel voor regel opsplitsen.

int checker = 0;We starten een checker waarmee we dubbele waarden kunnen vinden.

int val = str.charAt(i) – ‘a’;We krijgen de ASCII-waarde van het teken op de ‘i’-positie van de tekenreeks en trekken deze af met de ASCII-waarde van ‘een’. Aangezien de veronderstelling is dat de string alleen uit lagere tekens bestaat, is het aantal tekens beperkt tot 26. De waarde van ‘val’ is dus altijd >= 0.

if ((checker & (1 << val)) > 0) retourneert false;

checker |= (1 << waarde);

Dit is nu het lastige gedeelte. Laten we een voorbeeld bekijken met string “abcda”. Dit zou idealiter false moeten retourneren.

For loop iteratie 1:

Checker: 00000000000000000000000000000000

waarde: 97-97 = 0

1 << 0: 00000000000000000000000000000001

controleur & (1 << waarde): 00000000000000000000000000000000 is niet > 0

Vandaar controle: 00000000000000000000000000000001

For loop iteratie 2:

Checker: 00000000000000000000000000000001

waarde: 98-97 = 1

1 << 1: 00000000000000000000000000000010

controleur & (1 << waarde): 00000000000000000000000000000000 is niet > 0

Vandaar controle: 00000000000000000000000000000011

For loop iteratie 3:

Checker: 00000000000000000000000000000011

waarde: 99-97 = 2

1 << 2: 000000000000000000000000100

controleur & (1 << waarde): 00000000000000000000000000000000 is niet > 0

Vandaar controle: 0000000000000000000000000000000111

For loop iteratie 4:

Checker: 0000000000000000000000000000000111

waarde: 100-97 = 3

1 << 3: 00000000000000000000000000001000

controleur & (1 << waarde): 00000000000000000000000000000000 is niet > 0

Vandaar controle: 00000000000000000000000000001111

For loop iteratie 5:

Checker: 00000000000000000000000000001111

waarde: 97-97 = 0

1 << 0: 00000000000000000000000000000001

controleur & (1 << waarde): 00000000000000000000000000000001 is > 0

Retourneer daarom false.


Antwoord 7, autoriteit 2%

public static void main (String[] args)
{
    //In order to understand this algorithm, it is necessary to understand the following:
    //int checker = 0;
    //Here we are using the primitive int almost like an array of size 32 where the only values can be 1 or 0
    //Since in Java, we have 4 bytes per int, 8 bits per byte, we have a total of 4x8=32 bits to work with
    //int val = str.charAt(i) - 'a';
    //In order to understand what is going on here, we must realize that all characters have a numeric value
    for (int i = 0; i < 256; i++)
    {
        char val = (char)i;
        System.out.print(val);
    }
    //The output is something like:
    //             !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
    //There seems to be ~15 leading spaces that do not copy paste well, so I had to use real spaces instead
    //To only print the characters from 'a' on forward:
    System.out.println();
    System.out.println();
    for (int i=0; i < 256; i++)
    {
        char val = (char)i;
        //char val2 = val + 'a'; //incompatible types. required: char found: int
        int val2 = val + 'a';  //shift to the 'a', we must use an int here otherwise the compiler will complain
        char val3 = (char)val2;  //convert back to char. there should be a more elegant way of doing this.
        System.out.print(val3);
    }
    //Notice how the following does not work:
    System.out.println();
    System.out.println();
    for (int i=0; i < 256; i++)
    {
        char val = (char)i;
        int val2 = val - 'a';
        char val3 = (char)val2;
        System.out.print(val3);
    }
    //I'm not sure why this spills out into 2 lines:
    //EDIT I cant seem to copy this into stackoverflow!
    System.out.println();
    System.out.println();
    //So back to our original algorithm:
    //int val = str.charAt(i) - 'a';
    //We convert the i'th character of the String to a character, and shift it to the right, since adding shifts to the right and subtracting shifts to the left it seems
    //if ((checker & (1 << val)) > 0) return false;
    //This line is quite a mouthful, lets break it down:
    System.out.println(0<<0);
    //00000000000000000000000000000000
    System.out.println(0<<1);
    //00000000000000000000000000000000
    System.out.println(0<<2);
    //00000000000000000000000000000000
    System.out.println(0<<3);
    //00000000000000000000000000000000
    System.out.println(1<<0);
    //00000000000000000000000000000001
    System.out.println(1<<1);
    //00000000000000000000000000000010 == 2
    System.out.println(1<<2);
    //00000000000000000000000000000100 == 4
    System.out.println(1<<3);
    //00000000000000000000000000001000 == 8
    System.out.println(2<<0);
    //00000000000000000000000000000010 == 2
    System.out.println(2<<1);
    //00000000000000000000000000000100 == 4
    System.out.println(2<<2);
    // == 8
    System.out.println(2<<3);
    // == 16
    System.out.println("3<<0 == "+(3<<0));
    // != 4 why 3???
    System.out.println(3<<1);
    //00000000000000000000000000000011 == 3
    //shift left by 1
    //00000000000000000000000000000110 == 6
    System.out.println(3<<2);
    //00000000000000000000000000000011 == 3
    //shift left by 2
    //00000000000000000000000000001100 == 12
    System.out.println(3<<3);
    // 24
    //It seems that the -  'a' is not necessary
    //Back to if ((checker & (1 << val)) > 0) return false;
    //(1 << val means we simply shift 1 by the numeric representation of the current character
    //the bitwise & works as such:
    System.out.println();
    System.out.println();
    System.out.println(0&0);    //0
    System.out.println(0&1);       //0
    System.out.println(0&2);          //0
    System.out.println();
    System.out.println();
    System.out.println(1&0);    //0
    System.out.println(1&1);       //1
    System.out.println(1&2);          //0
    System.out.println(1&3);             //1
    System.out.println();
    System.out.println();
    System.out.println(2&0);    //0
    System.out.println(2&1);       //0   0010 & 0001 == 0000 = 0
    System.out.println(2&2);          //2  0010 & 0010 == 2
    System.out.println(2&3);             //2  0010 & 0011 = 0010 == 2
    System.out.println();
    System.out.println();
    System.out.println(3&0);    //0    0011 & 0000 == 0
    System.out.println(3&1);       //1  0011 & 0001 == 0001 == 1
    System.out.println(3&2);          //2  0011 & 0010 == 0010 == 2, 0&1 = 0 1&1 = 1
    System.out.println(3&3);             //3 why?? 3 == 0011 & 0011 == 3???
    System.out.println(9&11);   // should be... 1001 & 1011 == 1001 == 8+1 == 9?? yay!
    //so when we do (1 << val), we take 0001 and shift it by say, 97 for 'a', since any 'a' is also 97
    //why is it that the result of bitwise & is > 0 means its a dupe?
    //lets see..
    //0011 & 0011 is 0011 means its a dupe
    //0000 & 0011 is 0000 means no dupe
    //0010 & 0001 is 0011 means its no dupe
    //hmm
    //only when it is all 0000 means its no dupe
    //so moving on:
    //checker |= (1 << val)
    //the |= needs exploring:
    int x = 0;
    int y = 1;
    int z = 2;
    int a = 3;
    int b = 4;
    System.out.println("x|=1 "+(x|=1));  //1
    System.out.println(x|=1);     //1
    System.out.println(x|=1);      //1
    System.out.println(x|=1);       //1
    System.out.println(x|=1);       //1
    System.out.println(y|=1); // 0001 |= 0001 == ?? 1????
    System.out.println(y|=2); // ??? == 3 why??? 0001 |= 0010 == 3... hmm
    System.out.println(y);  //should be 3?? 
    System.out.println(y|=1); //already 3 so... 0011 |= 0001... maybe 0011 again? 3?
    System.out.println(y|=2); //0011 |= 0010..... hmm maybe.. 0011??? still 3? yup!
    System.out.println(y|=3); //0011 |= 0011, still 3
    System.out.println(y|=4);  //0011 |= 0100.. should be... 0111? so... 11? no its 7
    System.out.println(y|=5);  //so we're at 7 which is 0111, 0111 |= 0101 means 0111 still 7
    System.out.println(b|=9); //so 0100 |= 1001 is... seems like xor?? or just or i think, just or... so its 1101 so its 13? YAY!
    //so the |= is just a bitwise OR!
}
public static boolean isUniqueChars(String str) {
    int checker = 0;
    for (int i = 0; i < str.length(); ++i) {
        int val = str.charAt(i) - 'a';  //the - 'a' is just smoke and mirrors! not necessary!
        if ((checker & (1 << val)) > 0) return false;
        checker |= (1 << val);
    }
    return true;
}
public static boolean is_unique(String input)
{
    int using_int_as_32_flags = 0;
    for (int i=0; i < input.length(); i++)
    {
        int numeric_representation_of_char_at_i = input.charAt(i);
        int using_0001_and_shifting_it_by_the_numeric_representation = 1 << numeric_representation_of_char_at_i; //here we shift the bitwise representation of 1 by the numeric val of the character
        int result_of_bitwise_and = using_int_as_32_flags & using_0001_and_shifting_it_by_the_numeric_representation;
        boolean already_bit_flagged = result_of_bitwise_and > 0;              //needs clarification why is it that the result of bitwise & is > 0 means its a dupe?
        if (already_bit_flagged)
            return false;
        using_int_as_32_flags |= using_0001_and_shifting_it_by_the_numeric_representation;
    }
    return true;
}

Antwoord 8

Vorige berichten leggen goed uit wat het codeblok doet en ik wil mijn eenvoudige oplossing toevoegen met behulp van de BitSet java-gegevensstructuur:

private static String isUniqueCharsUsingBitSet(String string) {
  BitSet bitSet =new BitSet();
    for (int i = 0; i < string.length(); ++i) {
        int val = string.charAt(i);
        if(bitSet.get(val)) return "NO";
        bitSet.set(val);
    }
  return "YES";
}

9

Voor het geval dat iemand op zoek is naar Kotlin-equivalent van unieke tekens in een reeks met behulp van bit vector

fun isUnique(str: String): Boolean {
    var checker = 0
    for (i in str.indices) {
        val bit = str.get(i) - 'a'
        if (checker.and(1 shl bit) > 0) return false
        checker = checker.or(1 shl bit)
    }
    return true
}

Ref: https://www.programiz.com/kotlin-programming/bitwise

Other episodes