已發布·持續改進
位元運算 指南 · 5/6
本章目前僅提供英文版。
These five problems exercise the ideas from the earlier chapters: XOR cancellation, popcount, bitmask sets and bitmask DP. Try them yourself first, then compare with the approach and Python solution.
A door log records an employee's badge number once on the way in and once on the way out. Exactly one person has not left yet, so their number appears only once. Given the list of numbers, find that badge in O(n) time and O(1) extra space.
Approach: since a ^ a == 0, a ^ 0 == a, and XOR ignores order, XOR-ing the whole list cancels every pair and leaves the single badge. A hash set would also work but needs O(n) memory.
from functools import reduce
from operator import xor
def still_inside(badges: list[int]) -> int:
return reduce(xor, badges, 0)
print(still_inside([7, 3, 9, 3, 7])) # 9Given n, return a list with the number of set bits of every integer from 0 to n. Fill it in O(n) overall instead of counting each number from scratch.
Approach: i >> 1 is i with its lowest bit dropped. It is smaller than i, so its count is already known, and bits[i] = bits[i >> 1] + (i & 1). The rule bits[i] = bits[i & (i - 1)] + 1 works too.
def bit_table(n: int) -> list[int]:
bits = [0] * (n + 1)
for i in range(1, n + 1):
bits[i] = bits[i >> 1] + (i & 1)
return bits
print(bit_table(8)) # [0, 1, 1, 2, 1, 2, 2, 3, 1]
assert bit_table(1000) == [i.bit_count() for i in range(1001)]Start with n switches all off. Print an order that visits each of the 2^n states exactly once while changing only one switch per step. Such an order is a Gray code.
Approach: state i is i ^ (i >> 1). Going from i to i + 1 flips a run of low bits; XOR-ing that run with itself shifted right by one leaves a single bit, so neighbors differ in exactly one position. Verify by checking that each neighboring pair XORs to a value with popcount 1.
def gray_code(n: int) -> list[int]:
return [i ^ (i >> 1) for i in range(1 << n)]
codes = gray_code(3)
print([format(c, "03b") for c in codes])
assert len(set(codes)) == 8
assert all((a ^ b).bit_count() == 1 for a, b in zip(codes, codes[1:]))A project needs k skills (k ≤ 12) and there are m candidates, each with a list of skills and a cost. Find the minimum total cost of a team whose combined skills cover all k, or -1 if impossible.
Approach: encode each skill list as a k-bit mask. Let be the cheapest way to cover the skills in mask. Adding a candidate gives . Relaxing every mask for every candidate costs . Reusing the same candidate cannot help, because OR adds nothing new while the cost grows, so in-place updates are safe.
dp[mask]dp[mask | skill] = min(dp[mask | skill], dp[mask] + cost)O(m * 2^k)def min_team_cost(k: int, candidates: list[tuple[list[int], int]]) -> int:
full = (1 << k) - 1
INF = float("inf")
dp = [INF] * (1 << k)
dp[0] = 0
for skills, cost in candidates:
skill_mask = 0
for s in skills:
skill_mask |= 1 << s
for mask in range(1 << k):
if dp[mask] + cost < dp[mask | skill_mask]:
dp[mask | skill_mask] = dp[mask] + cost
return -1 if dp[full] == INF else dp[full]
people = [([0, 1], 5), ([2], 3), ([1, 2, 3], 7), ([3], 2), ([0], 1)]
print(min_team_cost(4, people)) # 8: [0] + [1, 2, 3]Seats are numbered 0 to n, but the sales list holds only n numbers, in no particular order. Find the one missing seat in O(n) time and O(1) extra space. Summing works too, but in fixed-width languages you would have to worry about overflow.
Approach: XOR every number from 0 to n together with every number in the list. Seats present on both sides cancel, leaving only the missing one. XOR never grows the value, so overflow is impossible.
def missing_seat(sold: list[int]) -> int:
result = len(sold) # n
for i, seat in enumerate(sold):
result ^= i ^ seat
return result
print(missing_seat([3, 0, 1])) # 2
print(missing_seat([0, 1, 2, 4, 5])) # 3XOR cancels pairs, i >> 1 and i & 1 reuse earlier answers, i ^ (i >> 1) produces a one-bit-at-a-time order, and using masks as array indices turns set-valued states into DP tables. When you meet a new problem, ask: are there at most about 20 items, do values come in pairs, are the states on/off? Those are the signs that bit manipulation fits.
0 則留言
登入 · 登入後即可留言。
來留下第一則留言吧。