Giải thuật 03/09/2026 8 phút

Cùng O(V+E), nhưng một cái ra đường 1998 bước, cái kia 499.500 bước

BFS và DFS được dạy như cặp sinh đôi cùng O(V+E), nên tưởng thay thế được. Nhưng trên lưới 1000×1000 chúng tìm thứ khác hẳn: BFS ra đường ngắn nhất 1998 cạnh, DFS ra đường 499.500 cạnh — dài gấp 250 lần. Bộ nhớ cũng phình theo hai chiều khác nhau. 'Cùng độ phức tạp' không có nghĩa 'cùng việc'. Tôi đo.

Giải thuật 03/09/2026 8 phút

Dijkstra trả về 4 khi đáp án đúng là 2 — chỉ vì một cạnh mang dấu trừ

Dijkstra là thuật toán tham lam nhưng đúng — nhờ đúng một điều kiện: trọng số không âm. Cho nó một cạnh âm (2→1 = -3), nó chốt dist[1]=4 sai trong khi đáp án thật là 2, mà không một cảnh báo. Và cấu trúc bên trong quyết định quy mô: heap nhanh hơn mảng 36 lần trên đồ thị thưa. Tôi đo.

Giải thuật 03/09/2026 8 phút

Cấu trúc 'gần như O(1)' này tụt thành O(n) nếu bạn quên đúng hai dòng

Union-Find không tự nhiên O(1): bản naive để cây thoái hóa thành chuỗi, đường find trung bình 9999 (=n/2), find hết mất 88 ms. Hai tối ưu vài dòng ép đường find về ~1, nhanh 3000 lần — và đẹp nhất, ở 10 triệu phần tử đường find trung bình vẫn phẳng lì ở 1,01. 'Gần O(1)' là sự thật đo được. Tôi đo.

Giải thuật 03/09/2026 7 phút

Thuật toán 'ngây thơ' O(n·m) hóa ra ngang KMP — trừ đúng một loại văn bản

Sách bảo naive O(n·m) chậm, phải dùng KMP. Nhưng trên văn bản ngẫu nhiên naive chỉ 1,04 so sánh mỗi ký tự — gần O(n), còn nhỉnh hơn KMP. O(n·m) là trường hợp xấu nhất, chỉ bật ra trên văn bản lặp (T='aaaa', P='aa..b') nơi KMP nhanh 194 lần. Nhãn xấu nhất không phải bản án cho mọi đầu vào. Tôi đo.

Giải thuật 03/09/2026 8 phút

'Chắc chắn O(n+m)' — bỏ quên một trong hai điều, Rabin-Karp chậm 33 lần

Rabin-Karp so khớp chuỗi bằng hash, được ghi là O(n+m). Nhưng con số đó đứng trên hai cái chân dễ quên: bỏ hash cuộn (tính lại mỗi cửa sổ) chậm 26 lần, dùng hash xấu trên văn bản lặp cho 999.001 va chạm giả và chậm 33 lần. Cả hai đều tụt về O(n·m) mà không một dòng lỗi. Tôi đo.

Giải thuật 03/09/2026 8 phút

Cấu trúc nói 'có thể có' này thay 25 MB bằng 1,2 MB — và không bao giờ nói dối một chiều

Bloom filter trả lời 'phần tử này có trong tập không' một cách không chính xác: dương tính giả 0,81% ở 10 bit/phần tử, 14,7% ở 4 bit, giảm theo hàm mũ khi thêm bit nhưng không bao giờ về 0. Đổi lại nó không bao giờ báo âm tính giả và chỉ tốn 1,2 MB thay vì 25 MB. Có số hàm băm tối ưu. Tôi đo.