Operator bitwise AND/OR/XOR/NOT, bit shifting, bitmasking untuk subset enumeration, serta trik efisien: cek ganjil/genap, toggle bit, isolasi rightmost 1, dan single-number dengan XOR.

Setelah di episode 11 kita membahas Backtracking, pada episode ini kita menutup FASE 3: SEARCHING & DIVIDE & CONQUER dengan bit manipulation — teknik yang beroperasi langsung pada representasi biner angka. Bit manipulation bukan hanya trik untuk competitive programming; ia adalah fondasi untuk memahami bagaimana komputer benar-benar bekerja dan mengapa operasi tertentu bisa dilakukan dalam satu langkah.
Menguasai bit manipulation memberikan keunggulan dalam optimasi — operasi bitwise seperti AND, OR, XOR, dan shift bisa menggantikan operasi yang lebih mahal secara komputasi. Di era AI apps, bit manipulation juga relevan untuk manipulasi bitmap, mask operations, dan efficient set operations.
| Operator | Simbol | Contoh (4-bit) |
|---|---|---|
| AND | & | 1010 & 1100 = 1000 |
| OR | | | 1010 | 1100 = 1110 |
| XOR | ^ | 1010 ^ 1100 = 0110 |
| NOT | ~ | ~1010 = ...0101 (complement) |
| Left shift | << | 1010 << 2 = 101000 |
| Right shift | >> | 1010 >> 1 = 0101 |
def is_odd(n):
return n & 1 # bit terakhir = 1 → ganjilLebih cepat dari n % 2 karena menghindari operasi modulo.
def toggle_bit(n, pos):
return n ^ (1 << pos)XOR dengan 1 di posisi tertentu akan mengubah bit di posisi itu tanpa mempengaruhi yang lain.
def isolate_rightmost_1(n):
return n & (-n)-n dalam two's complement adalah ~n + 1. n & (-n) menghasilkan hanya bit paling kanan yang bernilai 1.
def remove_rightmost_1(n):
return n & (n - 1)Operasi ini menghapus satu bit 1 setiap kali dipanggil — berguna untuk menghitung jumlah bit 1 (popcount).
def is_power_of_2(n):
return n > 0 and (n & (n - 1)) == 0Power of 2 hanya punya satu bit 1 → n & (n-1) menghapusnya → hasilnya 0.
Bitmask memungkinkan kita merepresentasikan subset dari set sebagai angka. Setiap bit merepresentasikan keberadaan sebuah elemen:
def enumerate_subsets(items):
n = len(items)
result = []
# 2^n subset: dari 000...0 sampai 111...1
for mask in range(1 << n):
subset = []
for i in range(n):
if mask & (1 << i):
subset.append(items[i])
result.append(subset)
return result
# enumerate_subsets(['A','B','C']) → 8 subsetKompleksitas: O(2^n × n) — efektif untuk n ≤ 20 (≈ 20 juta operasi).
Note
Bitmasking untuk subset enumeration adalah brute force yang dioptimasi. Untuk n > 20, brute force menjadi terlalu lambat — gunakan backtracking (episode 11) atau dynamic programming.
XOR memiliki properti unik: a ^ a = 0 dan a ^ 0 = a. Ini berarti XOR dari semua elemen kecuali satu yang muncul sekali akan menghasilkan elemen tersebut.
def single_number(nums):
"""Satu elemen muncul sekali, yang lain dua kali"""
result = 0
for num in nums:
result ^= num
return resultTime: O(n), Space: O(1) — tanpa hash map atau sorting.
| Pola | Trik |
|---|---|
| Cek bit ke-i | (n >> i) & 1 |
| Set bit ke-i | n | (1 << i) |
| Clear bit ke-i | n & ~(1 << i) |
| Toggle bit ke-i | n ^ (1 << i) |
| Hitung bit 1 | bin(n).count('1') atau loop n & (n-1) |
| Enumeration subset | Loop mask dari 0 sampai 2^n - 1 |
Tip
Bit manipulation menjadi powerful ketika dikombinasikan dengan DP (bitmask DP) untuk masalah seperti Travelling Salesman Problem pada graph kecil (n ≤ 20). State DP menggunakan bitmask untuk merepresentasikan set kota yang sudah dikunjungi.
Pada episode 12 ini, kalian telah memahami:
Ini menutup FASE 3: SEARCHING & DIVIDE & CONQUER. Di episode 13 selanjutnya kita masuk ke FASE 4: GREEDY & DYNAMIC PROGRAMMING — membahas Greedy Algorithms: prinsip greedy choice property, optimal substructure, dan masalah klasik seperti activity selection, Huffman coding, dan fractional knapsack. Sampai jumpa di episode 13!