Tôi tin rằng tôi đã đưa ra một cái gì đó nên hoạt động chung và hiệu quả nếu bạn được đảm bảo không có các bản sao * (tuy nhiên, nó có thể mở rộng cho bất kỳ số lượng lỗ và bất kỳ phạm vi số nguyên nào).
Ý tưởng đằng sau phương pháp này giống như quicksort, trong đó chúng ta tìm thấy một trục và phân vùng xung quanh nó, sau đó lặp lại ở một bên có một lỗ. Để xem bên nào có lỗ, chúng tôi tìm các số thấp nhất và cao nhất, và so sánh chúng với trục và số giá trị ở bên đó. Giả sử trục là 17 và số tối thiểu là 11. Nếu không có lỗ, cần có 6 số (11, 12, 13, 14, 15, 16, 17). Nếu có 5, chúng ta biết có một lỗ ở bên đó và chúng ta có thể tái diễn ở bên đó để tìm thấy nó. Tôi đang gặp khó khăn khi giải thích nó rõ ràng hơn thế, vì vậy hãy lấy một ví dụ.
15 21 10 13 18 16 22 23 24 20 17 11 25 12 14
Trục:
10 13 11 12 14 |15| 21 18 16 22 23 24 20 17 25
15 là trục, được biểu thị bằng ống ( ||
). Có 5 số ở bên trái của trục, vì sẽ có (15 - 10) và 9 ở bên phải, trong đó nên có 10 (25 - 15). Vì vậy, chúng tôi tái diễn ở phía bên phải; chúng tôi sẽ lưu ý rằng giới hạn trước là 15 trong trường hợp lỗ liền kề với nó (16).
[15] 18 16 17 20 |21| 22 23 24 25
Bây giờ có 4 số ở bên trái nhưng nên có 5 (21 - 16). Vì vậy, chúng tôi tái diễn ở đó và một lần nữa chúng tôi sẽ lưu ý ràng buộc trước đó (trong ngoặc).
[15] 16 17 |18| 20 [21]
Bên trái có đúng 2 số (18 - 16), nhưng bên phải có 1 thay vì 2 (20 - 18). Tùy thuộc vào điều kiện kết thúc của chúng tôi, chúng tôi có thể so sánh 1 số với hai bên (18, 20) và thấy rằng 19 bị thiếu hoặc lặp lại một lần nữa:
[18] |20| [21]
Phía bên trái có kích thước bằng 0, với một khoảng cách giữa trục (20) và ràng buộc trước đó (18), vì vậy 19 là lỗ.
*: Nếu có trùng lặp, có thể bạn có thể sử dụng bộ băm để loại bỏ chúng trong thời gian O (N), giữ nguyên phương thức O (N), nhưng điều đó có thể mất nhiều thời gian hơn so với sử dụng một số phương pháp khác.