Forberedelse til kodeinterviews · Lektion

Bitvise operatorer: AND, OR, XOR, NOT og skift

Gennemgå alle seks bitvise operatorer med sandhedstabeller og Python-eksempler, og forstå, hvordan venstre- og højreskift hænger sammen med multiplikation og division med to.

Lektion 1 af 413 trin

Bitvise operatorer: AND, OR, XOR, NOT og skift er en gratis Forberedelse til kodeinterviews-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i Forberedelse til kodeinterviews, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Forberedelse til kodeinterviews-kurset indeholder 4 lektioner i alt.

Hvorfor bitmanipulation er vigtig

Bitmanipulation lader dig arbejde direkte med heltals binære repræsentation. Mange problemer, der virker komplekse, bliver trivielle med det rette bitvise trick: at finde et manglende tal på O(n)-tid og O(1)-plads, at bytte variable uden en midlertidig variabel eller at kode delmængder kompakt. Interviewere bruger disse opgaver til at afprøve forståelse på lavt niveau og kreativ tænkning.

Heltal i Python har vilkårlig præcision — de kan være så store, som hukommelsen tillader — men bitoperationer følger altid standardsemantik for to-komplement på hardwareniveau. Alle seks operatorer arbejder bit for bit på heltallenes binære repræsentationer.

# All six bitwise operators in Python
a, b = 0b1010, 0b1100  # 10 and 12 in decimal
print(f'a = {bin(a)} = {a}')
print(f'b = {bin(b)} = {b}')
print(f'a & b  (AND) = {bin(a & b)} = {a & b}')   # 1000 = 8
print(f'a | b  (OR)  = {bin(a | b)} = {a | b}')   # 1110 = 14
print(f'a ^ b  (XOR) = {bin(a ^ b)} = {a ^ b}')   # 0110 = 6
print(f'~a     (NOT) = {~a}')                       # -11 (two's complement)
print(f'a << 1 (LSH) = {bin(a << 1)} = {a << 1}') # 10100 = 20
print(f'a >> 1 (RSH) = {bin(a >> 1)} = {a >> 1}') # 101 = 5

AND-operatoren: bitmaskering

AND-operatoren (&) giver kun 1, når begge inputbits er 1. Den bruges primært til maskering: at udvælge bestemte bits i et tal og samtidig nulstille alle andre. For at kontrollere, om bit k er sat i tallet n, skal du evaluere n & (1 << k) — hvis resultatet ikke er nul, er bit k lig med 1.

AND bruges også til at nulstille den laveste satte bit: n & (n - 1) fjerner bitten længst til højre med værdien 1. Det bruges til effektiv optælling af satte bits og til at kontrollere, om et tal er en potens af to (en potens af to har præcis én sat bit, så n & (n-1) == 0).

n = 0b10110100  # 180

# Check if bit 5 is set (0-indexed from right)
bit_5 = (n >> 5) & 1
print(f'Bit 5 of {n}: {bit_5}')  # 1

# Clear lowest set bit
print(f'n = {bin(n)}')
print(f'n & (n-1) = {bin(n & (n-1))}')  # 10110000, removed the '100'

# Check power of two
for x in [16, 15, 8, 6, 1, 0]:
    is_pow2 = x > 0 and (x & (x - 1)) == 0
    print(f'{x}: power of 2 = {is_pow2}')

OR-operatoren: sætning af bits

OR-operatoren (|) giver 1, hvis mindst én inputbit er 1. Den bruges primært til at sætte en bestemt bit til 1 uden at påvirke de andre. For at sætte bit k i tallet n skal du bruge n | (1 << k). Den 1'er, der forskydes til position k, tænder den pågældende bit; alle andre bits forbliver uændrede, fordi OR med 0 bevarer værdien.

OR bruges også til at kombinere flag: Hvis du repræsenterer funktionsflag som individuelle bits, kan du aktivere flere flag med OR. Eksempelvis kombinerer READ | WRITE | EXECUTE tre tilladelsesbits til ét heltal.

# Set bit k in n
def set_bit(n, k):
    return n | (1 << k)

n = 0b1000  # 8
print(f'Original: {bin(n)}')
print(f'Set bit 1: {bin(set_bit(n, 1))}')  # 1010
print(f'Set bit 0: {bin(set_bit(n, 0))}')  # 1001

# Flag combination example
READ    = 0b001  # 1
WRITE   = 0b010  # 2
EXECUTE = 0b100  # 4

perms = READ | EXECUTE
print(f'READ|EXECUTE permissions: {bin(perms)} = {perms}')
print(f'Has READ:    {bool(perms & READ)}')
print(f'Has WRITE:   {bool(perms & WRITE)}')
print(f'Has EXECUTE: {bool(perms & EXECUTE)}')

XOR-operatoren: skift og forskel

XOR-operatoren (^) giver 1, når inputbittene er forskellige. XOR har tre stærke algebraiske egenskaber: a ^ a = 0 (ens input ophæver hinanden), a ^ 0 = a (nul er identitetselementet), og XOR er både kommutativ og associativ. Disse egenskaber gør XOR til det oplagte værktøj til at finde entydige elementer.

XOR bruges også til at skifte en bestemt bit: n ^ (1 << k) vender bit k, mens de andre forbliver uændrede. Hvis bit k var 0, bliver den 1; hvis den var 1, bliver den 0.

# XOR properties
print(5 ^ 5)    # 0 — same values cancel
print(5 ^ 0)    # 5 — zero is identity
print(5 ^ 3 ^ 3)  # 5 — 3 cancels itself

# Toggle bit k
def toggle_bit(n, k):
    return n ^ (1 << k)

n = 0b1010
print(f'Toggle bit 3: {bin(toggle_bit(n, 3))}')  # 0010 (was 1)
print(f'Toggle bit 0: {bin(toggle_bit(n, 0))}')  # 1011 (was 0)

# XOR swap without temp variable
a, b = 7, 13
a = a ^ b
b = a ^ b   # b now gets original a
a = a ^ b   # a now gets original b
print(f'After XOR swap: a={a}, b={b}')  # a=13, b=7

NOT-operatoren og to-komplement

NOT-operatoren (~) inverterer alle bits. I Python er ~n lig med -(n+1) på grund af to-komplementrepræsentationen. Det overrasker mange: ~5 = -6, ikke den naivt forventede 0b11111010. Heltal i Python har uendelig præcision, så hvis du vender alle bits i et positivt tal, får du et negativt resultat i to-komplement.

I praksis bruger du sjældent ~ alene i Python til bitmanipulation. Brug det i stedet sammen med AND til at nulstille bestemte bits, eller beregn ~n & mask, hvor mask begrænser bredden til et bestemt antal bits (f.eks. & 0xFFFFFFFF for 32-bit).

# NOT in Python: ~n = -(n+1)
for n in [0, 1, 5, 127]:
    print(f'~{n} = {~n}')   # all give -(n+1)

# Clear bit k using NOT
def clear_bit(n, k):
    return n & ~(1 << k)

n = 0b1111
print(f'Clear bit 2: {bin(clear_bit(n, 2))}')  # 1011
print(f'Clear bit 0: {bin(clear_bit(n, 0))}')  # 1110

# Limiting to 32-bit with mask
def bitwise_not_32(n):
    return ~n & 0xFFFFFFFF

print(f'32-bit NOT of 5: {bin(bitwise_not_32(5))}')  # 32 zeros then ones

Venstreforskydning: multiplikation med potenser af to

Venstreforskydningsoperatoren (<<) forskyder alle bits mod venstre med k positioner og udfylder de ledige positioner til højre med nuller. Det svarer til at multiplicere med 2^k. En venstreforskydning med 1 fordobler værdien; en venstreforskydning med k multiplicerer med 2^k.

I interviewopgaver bruges venstreforskydninger oftest til at oprette bitmasker: 1 << k opretter et tal, hvor kun bit k er sat. Det er grundlaget for alle bitmanipulationsoperationer — at sætte, nulstille, skifte og kontrollere individuelle bits begynder med 1 << k.

# Left shift = multiply by 2^k
n = 1
for k in range(8):
    print(f'1 << {k} = {1 << k}')   # 1,2,4,8,16,32,64,128

# Practical use: creating bitmasks
def bit_mask(k):
    return 1 << k

print(f'\nBitmask for bit 0: {bin(bit_mask(0))}')  # 1
print(f'Bitmask for bit 3: {bin(bit_mask(3))}')  # 1000
print(f'Bitmask for bit 7: {bin(bit_mask(7))}')  # 10000000

# Fast exponentiation: 2^10 = 1024
print(f'2^10 = {1 << 10}')  # 1024

Højreforskydning: division med potenser af to

Højreforskydningsoperatoren (>>) forskyder alle bits mod højre med k positioner og kasserer de k bits længst til højre. Det svarer til heltalsdivision med 2^k. Højreforskydning i Python er altid aritmetisk: de bits, der kommer ind længst til venstre, udfyldes med fortegnsbitten (0 for positive tal, 1 for negative).

Et almindeligt interviewtrick er at udtrække bit k fra tallet n med (n >> k) & 1. Det forskyder bit k ned til position 0 og maskerer alle andre bits væk. Det er den enkleste måde at kontrollere en bestemt bit på uden at skulle beregne og sammenligne en komplet maske.

# Right shift = integer division by 2^k
n = 64
for k in range(7):
    print(f'{n} >> {k} = {n >> k}')   # 64,32,16,8,4,2,1

# Extract bit k from n
def get_bit(n, k):
    return (n >> k) & 1

n = 0b10110101  # 181
print(f'\nBits of {n} ({bin(n)}):')
for k in range(8):
    print(f'  Bit {k}: {get_bit(n, k)}')

# Negative number right shift (arithmetic)
print(f'-8 >> 1 = {-8 >> 1}')   # -4 (fills with sign bit 1)

Huskeliste over praktiske bittricks

Her er en samling af de mest almindelige idiomer inden for bitmanipulation, som du vil møde i interviews. Lær disse mønstre udenad — de går igen i dusinvis af opgaver:

  • n & 1 — kontrollér, om n er ulige
  • n & (n-1) — nulstil den laveste satte bit
  • n & -n — isolér den laveste satte bit
  • n | (1 << k) — sæt bit k
  • n & ~(1 << k) — nulstil bit k
  • n ^ (1 << k) — skift bit k
  • (n >> k) & 1 — kontrollér bit k
# Bit trick cheatsheet — all at once
n = 0b10110100  # 180

print(f'n = {bin(n)} = {n}')
print(f'n & 1       (odd check)         = {n & 1}')          # 0: even
print(f'n & (n-1)   (clear lowest bit)  = {bin(n & (n-1))}')
print(f'n & -n      (isolate lowest bit) = {bin(n & -n)}')
print(f'n | (1<<1)  (set bit 1)          = {bin(n | (1<<1))}')
print(f'n & ~(1<<2) (clear bit 2)        = {bin(n & ~(1<<2))}')
print(f'n ^ (1<<5)  (toggle bit 5)       = {bin(n ^ (1<<5))}')
print(f'(n>>4) & 1  (check bit 4)        = {(n>>4) & 1}')

Optælling af satte bits (popcount)

At tælle antallet af bits med værdien 1 i et heltal kaldes bitoptælling (popcount). Den naive tilgang gennemløber alle bits. Brian Kernighan-tricket er hurtigere: nulstil gentagne gange den laveste satte bit med n &= n - 1, og tæl iterationerne, indtil n bliver 0. Hver iteration fjerner præcis én bit med værdien 1, så løkken kører nøjagtig lige så mange gange, som der er bits med værdien 1.

Python 3.10+ har int.bit_count(), som returnerer antallet direkte. I ældre versioner er Kernighan-tricket den almindelige manuelle tilgang. Denne teknik løser også problemet 'Hamming-vægt' på LeetCode.

# Method 1: naive O(log n)
def count_bits_naive(n):
    count = 0
    while n:
        count += n & 1
        n >>= 1
    return count

# Method 2: Brian Kernighan O(k) where k = number of set bits
def count_bits_fast(n):
    count = 0
    while n:
        n &= n - 1   # clear lowest set bit
        count += 1
    return count

# Method 3: Python built-in (3.10+)
# n.bit_count()

for x in [0, 1, 7, 255, 180, 1024]:
    naive = count_bits_naive(x)
    fast  = count_bits_fast(x)
    print(f'{x:4d} ({bin(x):10s}): naive={naive}, fast={fast}')

Vigtige faldgruber ved bitmanipulation i Python

I modsætning til C/Java er heltal i Python vilkårligt store — der findes ikke 32-bit- eller 64-bit-overløb. Derfor skal du selv maskere resultater til en fast bredde, når du løser opgaver, der forventer 32-bit-adfærd: brug & 0xFFFFFFFF for kun at beholde de nederste 32 bits.

NOT-operatoren ~n i Python returnerer -(n+1), ikke den bitinverterede version, som du måske forventer fra C. I 32-bit-opgaver skal du bruge ~n & 0xFFFFFFFF eller beregne 0xFFFFFFFF ^ n for at få det forventede 32-bit-komplement. Disse forskelle volder problemer for mange kandidater, der er vant til bitmanipulation i C-stil.

# Python vs C gotchas
# In C: unsigned 32-bit NOT of 5 = 4294967290
# In Python: ~5 = -6
print(f'Python ~5 = {~5}')              # -6
print(f'32-bit ~5 = {~5 & 0xFFFFFFFF}') # 4294967290

# No integer overflow in Python
big = 1 << 100   # 2^100: huge number, no overflow
print(f'2^100 = {big}')  # works fine

# Right shift on negatives: arithmetic (sign-extending)
print(f'-1 >> 3 = {-1 >> 3}')   # -1 (all ones shifted in)

# Safe 32-bit mask for problems expecting C/Java semantics
MASK32 = 0xFFFFFFFF
result = (5 + 0xFFFFFFFE) & MASK32  # simulates 32-bit overflow
print(f'5 + (-2) in 32-bit = {result}')  # 3

Skiftoperatorer og multiplikation

Venstre- og højreforskydninger er en ekstremt hurtig måde at multiplicere eller dividere med potenser af to på. På hardware er bitforskydninger operationer med én instruktion, mens multiplikation og division kræver flere cyklusser. I Python er heltalsmultiplikation allerede effektiv, men forståelsen af sammenhængen hjælper dig med at se bitmønstre tydeligere.

En nyttig identitet er: For at kontrollere, om n er et multiplum af 2^k, skal du bruge (n & (2^k - 1)) == 0. Masken 2^k - 1 har alle de nederste k bits sat til 1; en AND-operation med den giver resten ved division med 2^k. Det svarer til n % (2^k), men er hurtigere i C-baserede sprog.

# Shift vs arithmetic equivalence
for k in range(1, 5):
    n = 48
    print(f'{n} * 2^{k} = {n * (2**k)} = {n << k} (left shift)')
    print(f'{n} // 2^{k} = {n // (2**k)} = {n >> k} (right shift)')
    print()

# Check divisibility by power of 2
def divisible_by_power_of_2(n, k):
    mask = (1 << k) - 1   # 2^k - 1: lower k bits all 1
    return (n & mask) == 0

for n in [16, 24, 32, 15, 100]:
    print(f'{n} divisible by 4? {divisible_by_power_of_2(n, 2)}')

Hurtigt tjek

Afprøv din forståelse af begreberne fra Data Structures & Algorithms — Coding Interview Prep i denne lektion.

Opsummering af lektionen

I denne lektion lærte du, at: AND maskerer bits, OR sætter bits, XOR skifter bits og registrerer forskelle, NOT inverterer (giver -(n+1) i Python), og forskydninger multiplicerer/dividerer med potenser af to, n & (n-1) nulstiller den laveste satte bit og danner grundlag for kontrol af potenser af to og bitoptælling, og Python har ikke overløb med fast bredde, så 32-bit-opgaver kræver eksplicit maskering med & 0xFFFFFFFF. Næste lektion undersøger vi XOR's selv-inverse egenskab for at løse familien af problemer med ét enkelt tal.

Gratis at komme i gang

Lær Forberedelse til kodeinterviews med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
90
Lektioner
360

Ofte stillede spørgsmål

Er lektionen “Bitvise operatorer: AND, OR, XOR, NOT og skift” gratis?

Ja — hele teksten til “Bitvise operatorer: AND, OR, XOR, NOT og skift” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af Forberedelse til kodeinterviews-kurset, skal du opgradere til CoddyKit PRO. Forberedelse til kodeinterviews-kurset indeholder 4 lektioner i alt.

Hvad lærer jeg i “Bitvise operatorer: AND, OR, XOR, NOT og skift”?

Gennemgå alle seks bitvise operatorer med sandhedstabeller og Python-eksempler, og forstå, hvordan venstre- og højreskift hænger sammen med multiplikation og division med to. Du øver dig i Forberedelse til kodeinterviews med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Forberedelse til kodeinterviews?

Der kræves ingen tidligere erfaring. Forberedelse til kodeinterviews på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.

Hvor lang tid tager lektionen “Bitvise operatorer: AND, OR, XOR, NOT og skift”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Forberedelse til kodeinterviews-lektion?

Ja. Alle Forberedelse til kodeinterviews-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Bitvise operatorer: AND, OR, XOR, NOT og skift
  2. Single Number og XOR-egenskaber
  3. Bitmasker: Sæt, ryd, skift og kontrollér
  4. Optælling af bit, manglende tal og omvendte bit
← Tilbage til Forberedelse til kodeinterviews