Luyện tập Bit Manipulation
Bài 1:
Cho 2 số n và m, chèn tất cả các bit của m vào n theo khoảng từ i đến j. Có thể chắc chắn là số lượng bit của n luôn lớn hơn m, và i-j = số lượng bit của m.
Ví dụ:
Input: n = 1024
m = 19
i = 2
j = 6
Output: n = 1100
Giải thích
(1024)10 = (10000000000)2
(19)10 = (10011)2
kết quả : (10001001100)2 = (1100)10
Cách làm như sau
1. xoá toàn bộ bit từ i đến j (về 0) của n
2. dịch m sang trái i bit
3. trả về kết quả m & n
Bước 1 là khó nhất, chúng ta áp dụng cách làm thông thường là tạo mặt nạ.
Mặt nạ của chúng ta gồm 3 phần, bên trái j, bên phải i là 1, ở giữa i j là 0.
let allOnes = ~0
let left = allOnes << (j + 1)
let right = ((1 << i) - 1)
let mask = left | right
sau đó chỉ cần & n với mặt nạ vừa tạo là xong.
Bài 2:
Cho một số nguyên và một lần duy nhất đổi bit 0 thành bit 1. Cài đặt hàm tìm chuỗi 1 dài nhất sau khi thực một lần đổi bit.
Ví dụ:
Input: 1775 (tương ứng: 11011101111)
Output: 8
Gỉai thích: nếu đổi bit thứ 9 thì có chuỗi 1 dài nhất là 6, đổi bit thứ 5 ta có chuỗi 8
Hmm, giải như thế nào đây ta?
Ý tưởng đầu tiên của mình là đếm toàn bộ số 1 bên trái và phải của toàn bộ số 0, sau đó trả về max tổng trái phải….
ví dụ 101110111, phải của 0 đầu là 3, trái là 3, phải 0 sau là 3, trái là 1, vậy kết quả sẽ là max( 3+3, 3+1) + 1 = 7.
Nếu duyệt 2 lần thì sẽ double work việc tìm 1 trái phải, nên chúng ta có cách duyệt tối ưu hơn là đếm 1 đến khi gặp 0 thì gán bên phải là hiệu của index hiện tại với index 0 tìm thấy trước đó, bên trái sẽ được tính cho đến khi gặp 0 tiếp theo, thực hiện update lại max nếu cần.
func flipToWin(_ input: Int) -> Int {
var maxLength = 0
var currentLength = 0
var previousLength = 0
var clone = input
while clone > 0 {
let num = clone & 1
if num == 1 {
currentLength += 1
} else {
previousLength = (clone & 2) == 0 ? 0 : currentLength
currentLength = 0
}
maxLength = max(previousLength + currentLength, maxLength);
clone >>= 1
}
return maxLength + 1
}
Happy Coding!