Mục lục
1. Bỏ log khỏi đoạn mã cần đo
Vấn đề. Nếu bạn gọiconsole.log(bucket) trong vòng lặp hoặc ngay trước khi trả kết quả, thời gian đo sẽ bao gồm cả việc định dạng và ghi dữ liệu ra console. Với cấu trúc lớn như mảng bucket, phần việc đó có thể che khuất thời gian của thuật toán.
console.log() là I/O đồng bộ: với Node.js, hành vi đồng bộ hay bất đồng bộ phụ thuộc vào stream và môi trường chạy. Điều chắc chắn là log thêm công việc ngoài thuật toán vào phép đo. Xem tài liệu console của Node.js.
2. Dùng bucket cho bài toán Top K Frequent Elements
Vấn đề. Một cách giải phổ biến là đếm tần suất, rồi sắp xếp các số theo tần suất. Nếu cóm số khác nhau, bước sắp xếp theo so sánh thường tốn O(m log m) thời gian.
Cách làm. Với n = nums.length, tần suất của một số chỉ có thể nằm từ 1 đến n. Tạo n + 1 bucket, trong đó bucket[count] chứa các số xuất hiện count lần. Sau đó duyệt từ bucket có tần suất cao nhất và dừng khi đã lấy đủ k số.
Map có chi phí trung bình hằng số, đếm mất O(n), tạo bucket mất O(n), phân nhóm và duyệt ngược cũng mất tối đa O(n). Tổng thời gian trung bình và bộ nhớ đều là O(n). Đổi lại, bạn cấp phát n + 1 mảng bucket, kể cả khi chỉ có vài tần suất được dùng. Nếu cần thứ tự ổn định giữa các số có cùng tần suất, hãy định nghĩa thêm quy tắc sắp xếp cho trường hợp bằng nhau.
Cách đánh giá một thay đổi
Đầu tiên, kiểm tra kết quả với mảng rỗng,k = 0, số âm và các số có cùng tần suất. Tiếp theo, đo trên dữ liệu gần với đầu vào thật, giữ nguyên môi trường chạy và bỏ log khỏi đoạn mã được đo. Ưu tiên thay đổi độ phức tạp trước; chỉ giữ một tối ưu ở cấp cú pháp nếu phép đo cho thấy nó giúp ích mà vẫn dễ đọc.