โจทย์
เขียนโปรแกรมตรวจสอบว่าตัวเลขที่กำหนดเป็นพหุคูณของ 3 (หาร 3 ลงตัว) หรือไม่
วิธีทั่วไป (Naive)
รวมหลักของตัวเลขทั้งหมด หากผลรวมหาร 3 ลงตัว ตัวเลขก็หาร 3 ลงตัว
Time: O(log10 n) - ต้องดึงทุกหลัก
วิธีที่มีประสิทธิภาพ (Efficient) - ใช้ Bit Counting
ทฤษฎี: ใน binary representation หาก ความต่างระหว่างจำนวนบิต 1 ที่ตำแหน่งคี่ และตำแหน่งคู่ เป็นพหุคูณของ 3 ตัวเลขก็จะเป็นพหุคูณของ 3
ตัวอย่าง: n = 24 (binary: 11000)
ตำแหน่งคี่ (1, 3, 5...): บิต 1 อยู่ที่ตำแหน่ง 3 และ 4? รอ 24 = 110002 = 16+8
bit 4 (16's place): 1 (even position - 0-indexed: 4)
bit 3 (8's place): 1 (odd position: 3)
Even bits: 1, Odd bits: 1, Diff = 0 → หาร 3 ลงตัว ✓
โค้ดตัวอย่าง
#include <bits/stdc++.h>
using namespace std;
bool isDivisibleBy3(int n) {
int oddBitCount = 0;
int evenBitCount = 0;
if (n < 0) n = -n; // handle negative
if (n == 0) return true;
if (n == 1) return false;
while (n) {
if (n & 1) oddBitCount++; // bit 0 (LSB) = odd position
if (n & 2) evenBitCount++; // bit 1 = even position
n >>= 2; // shift 2 bits ทีละครั้ง
}
return isDivisibleBy3(abs(oddBitCount - evenBitCount));
}
int main() {
int n = 1241;
cout << "The number " << n;
if (isDivisibleBy3(n)) cout << " is a multiple of 3";
else cout << " is not a multiple of 3";
return 0;
}
ผลลัพธ์
The number 1241 is not a multiple of 3
การทำงานของอัลกอริทึม
- นับบิต 1 ที่ตำแหน่งคี่ (0, 2, 4, ...) → oddBitCount
- นับบิต 1 ที่ตำแหน่งคู่ (1, 3, 5, ...) → evenBitCount
- คำนวณความต่าง |odd - even|
- Recursive เรียกฟังก์ชันซ้ำจนได้คำตอบ (base case: 0=true, 1=false)
Complexity
- Time: O(log2 n) - จำนวนบิตของ n
- Space: O(log2 n) - recursion depth (สามารถทำ iterative ได้)
Iterative Version (หลีกเลี่ยง Recursion)
bool isDivisibleBy3Iterative(int n) {
if (n < 0) n = -n;
while (n >= 3) { // ลดขนาดจนเหลือ 0,1,2
int odd = 0, even = 0;
while (n) {
if (n & 1) odd++;
if (n & 2) even++;
n >>= 2;
}
n = abs(odd - even);
}
return n == 0;
}
สรุป
วิธี Bit Counting นี้มีประสิทธิภาพทางทฤษฎี (O(log n) bit operations) แต่ในทางปฏิบัติบน CPU สูงสุด n % 3 == 0 เร็วกว่ามาก เพราะมี hardware division instruction วิธีนี้เหมาะสำหรับระบบที่ไม่มี division instruction หรือการศึกษาอัลกอริทึม