Điều gì sẽ khiến một thuật toán có độ phức tạp O (log log n)?


Câu trả lời:


217

Các điều khoản O (log log n) có thể hiển thị ở nhiều nơi khác nhau, nhưng thường có hai tuyến đường chính sẽ đến trong thời gian chạy này.

Thu nhỏ bởi một căn bậc hai

Như đã đề cập trong câu trả lời cho câu hỏi được liên kết, một cách phổ biến để một thuật toán có độ phức tạp theo thời gian O (log n) là để thuật toán đó hoạt động bằng cách cắt giảm nhiều lần kích thước của đầu vào theo một số yếu tố không đổi trên mỗi lần lặp. Nếu đúng như vậy, thuật toán phải kết thúc sau lần lặp O (log n), bởi vì sau khi thực hiện phép chia O (log n) cho một hằng số, thuật toán phải thu nhỏ kích thước bài toán xuống 0 hoặc 1. Đây là lý do, ví dụ: , tìm kiếm nhị phân có độ phức tạp O (log n).

Thật thú vị, có một cách tương tự để thu nhỏ kích thước của một bài toán tạo ra thời gian chạy có dạng O (log log n). Thay vì chia đầu vào làm đôi ở mỗi lớp, điều gì sẽ xảy ra nếu chúng ta lấy căn bậc hai của kích thước ở mỗi lớp?

Ví dụ, hãy lấy số 65,536. Chúng ta phải chia bao nhiêu lần cho 2 cho đến khi bớt 1? Nếu chúng tôi làm điều này, chúng tôi nhận được

  • 65,536 / 2 = 32,768
  • 32,768 / 2 = 16,384
  • 16,384 / 2 = 8,192
  • 8.192 / 2 = 4.096
  • 4,096 / 2 = 2,048
  • 2.048 / 2 = 1.024
  • 1,024 / 2 = 512
  • 512/2 = 256
  • 256/2 = 128
  • 128/2 = 64
  • 64/2 = 32
  • 32/2 = 16
  • 16/2 = 8
  • 8/2 = 4
  • 4/2 = 2
  • 2/2 = 1

Quá trình này thực hiện 16 bước và cũng có trường hợp 65,536 = 2 16 .

Nhưng, nếu chúng ta lấy căn bậc hai ở mỗi cấp, chúng ta nhận được

  • √65,536 = 256
  • √256 = 16
  • √16 = 4
  • √4 = 2

Lưu ý rằng chỉ mất bốn bước để giảm tất cả xuống còn 2. Tại sao lại như vậy?

Đầu tiên, một lời giải thích trực quan. Hai số n và √n có tất cả bao nhiêu chữ số? Có xấp xỉ log n chữ số trong số n và xấp xỉ log (√n) = log (n 1/2 ) = (1/2) log n chữ số trong √n. Điều này có nghĩa là, mỗi khi bạn lấy căn bậc hai, bạn sẽ giảm đi một nửa số chữ số trong số. Bởi vì bạn chỉ có thể giảm một nửa đại lượng k O (log k) lần trước khi nó giảm xuống một hằng số (giả sử, 2), điều này có nghĩa là bạn chỉ có thể lấy căn bậc hai O (log log n) lần trước khi bạn giảm số đó xuống. thành một hằng số nào đó (giả sử, 2).

Bây giờ, chúng ta hãy làm một số phép toán để làm cho điều này nghiêm ngặt. Hãy viết lại chuỗi trên dưới dạng lũy ​​thừa của hai:

  • √65,536 = √2 16 = (2 16 ) 1/2 = 2 8 = 256
  • √256 = √2 8 = (2 8 ) 1/2 = 2 4 = 16
  • √16 = √2 4 = (2 4 ) 1/2 = 2 2 = 4
  • √4 = √2 2 = (2 2 ) 1/2 = 2 1 = 2

Chú ý rằng chúng ta đã làm theo dãy 2 16 → 2 8 → 2 4 → 2 2 → 2 1 . Trên mỗi lần lặp, chúng tôi cắt số mũ của lũy thừa của hai thành một nửa. Điều đó thật thú vị, bởi vì điều này kết nối trở lại những gì chúng ta đã biết - bạn chỉ có thể chia số k trong một nửa O (log k) lần trước khi nó giảm xuống 0.

Vậy lấy số n bất kỳ và viết thành n = 2 k . Mỗi khi bạn lấy căn bậc hai của n, bạn giảm một nửa số mũ trong phương trình này. Do đó, chỉ có thể có O (log k) căn bậc hai được áp dụng trước khi k giảm xuống 1 hoặc thấp hơn (trong trường hợp này n giảm xuống 2 hoặc thấp hơn). Vì n = 2 k , điều này có nghĩa là k = log 2 n, và do đó số căn bậc hai được lấy là O (log k) = O (log log n). Do đó, nếu có thuật toán hoạt động bằng cách liên tục giảm bài toán thành bài toán con có kích thước là căn bậc hai của kích thước bài toán ban đầu, thuật toán đó sẽ kết thúc sau O (log log n) bước.

Một ví dụ thực tế về điều này là cây van Emde Boas(vEB-tree) cấu trúc dữ liệu. VEB-tree là một cấu trúc dữ liệu chuyên dụng để lưu trữ các số nguyên trong phạm vi 0 ... N - 1. Nó hoạt động như sau: nút gốc của cây có √N con trỏ trong đó, tách phạm vi 0 ... N - 1 thành √N thùng, mỗi thùng chứa một dải khoảng √N số nguyên. Các nhóm này sau đó được chia nhỏ bên trong mỗi nhóm thành √ (√ N) nhóm, mỗi nhóm chứa khoảng √ (√ N) phần tử. Để đi ngang qua cây, bạn bắt đầu từ gốc, xác định bạn thuộc nhóm nào, sau đó tiếp tục đệ quy trong cây con thích hợp. Do cách cấu trúc của vEB-tree, bạn có thể xác định trong thời gian O (1) cây con nào sẽ đi xuống, và vì vậy sau các bước O (log log N), bạn sẽ đến dưới cùng của cây. Theo đó, việc tra cứu trong một vEB-tree chỉ mất thời gian O (log log N).

Một ví dụ khác là thuật toán cặp điểm gần nhất Hopcroft-Fortune . Thuật toán này cố gắng tìm hai điểm gần nhất trong tập hợp các điểm 2D. Nó hoạt động bằng cách tạo một lưới các nhóm và phân phối điểm vào các nhóm đó. Nếu tại bất kỳ điểm nào trong thuật toán tìm thấy một nhóm có nhiều hơn √N điểm trong đó, thuật toán sẽ xử lý một cách đệ quy nhóm đó. Do đó, độ sâu tối đa của đệ quy là O (log log n), và sử dụng phân tích cây đệ quy, có thể chỉ ra rằng mỗi lớp trong cây đều hoạt động O (n). Do đó, tổng thời gian chạy của thuật toán là O (n log log n).

Các thuật toán O (log n) trên Đầu vào Nhỏ

Có một số thuật toán khác đạt được thời gian chạy O (log log n) bằng cách sử dụng các thuật toán như tìm kiếm nhị phân trên các đối tượng có kích thước O (log n). Ví dụ, cấu trúc dữ liệu trie x-fast thực hiện tìm kiếm nhị phân trên các lớp của cây có chiều cao O (log U), do đó thời gian chạy cho một số hoạt động của nó là O (log log U). Trie y-fast có liên quan nhận được một số thời gian chạy O (log log U) của nó bằng cách duy trì các BST cân bằng của mỗi nút O (log U), cho phép các tìm kiếm trong các cây đó chạy trong thời gian O (log log U). Cây tango và các cấu trúc dữ liệu cây đa dạng có liên quan kết thúc bằng một thuật ngữ O (log log n) trong các phân tích của chúng vì chúng duy trì các cây chứa các mục O (log n).

Những ví dụ khác

Các thuật toán khác đạt được thời gian chạy O (log log n) theo những cách khác. Tìm kiếm nội suy dự kiến ​​thời gian chạy O (log log n) để tìm một số trong một mảng đã sắp xếp, nhưng việc phân tích khá liên quan. Cuối cùng, phân tích hoạt động bằng cách chỉ ra rằng số lần lặp bằng số k sao cho n 2 -k ≤ 2, với log log n là nghiệm đúng. Một số thuật toán, như thuật toán Cheriton-Tarjan MST , đi đến thời gian chạy liên quan đến O (log log n) bằng cách giải một bài toán tối ưu hóa có ràng buộc phức tạp.

Hi vọng điêu nay co ich!


5
@ JonathonReinhart- Đây chỉ là một thứ mà tôi nghĩ là (a) thực sự, rất hay và (b) không được nhiều người biết đến. Tôi luôn vui mừng được chia sẻ những điều như thế này! :-)
templatetypedef


chỉ cần đoán những hàm ý khác mà "Trả lời câu hỏi của riêng bạn" ở cuối trang Đặt câu hỏi có thể có hoặc nó chỉ bật hộp văn bản trả lời trên trang câu hỏi.
Mahesha999,

1
Dòng quan trọng: Do đó, nếu có thuật toán hoạt động bằng cách liên tục giảm bài toán thành bài toán con có kích thước là căn bậc hai của kích thước bài toán ban đầu, thuật toán đó sẽ kết thúc sau O (log log n) bước.
Gun2sh

3

Một cách để xem hệ số O (log log n) theo độ phức tạp thời gian là bằng phép chia giống như nội dung được giải thích trong câu trả lời khác, nhưng có một cách khác để xem hệ số này, khi chúng ta muốn thực hiện sự cân bằng giữa thời gian và không gian / thời gian. và xấp xỉ / thời gian và độ cứng / ... của các thuật toán và chúng tôi có một số lần lặp nhân tạo trên thuật toán của mình.

Ví dụ: SSSP (Đường đi ngắn nhất nguồn đơn) có thuật toán O (n) trên đồ thị phẳng, nhưng trước thuật toán phức tạp đó đã có một thuật toán dễ hơn nhiều (nhưng vẫn khá khó) với thời gian chạy O (n log log n), cơ sở của thuật toán như sau (chỉ là mô tả rất sơ bộ và tôi đề nghị bỏ qua việc hiểu phần này và đọc phần khác của câu trả lời):

  1. chia đồ thị thành các phần có kích thước O (log n / (log log n)) với một số hạn chế.
  2. Giả sử mỗi phần được đề cập là nút trong đồ thị mới G 'sau đó tính SSSP cho G' trong thời gian O (| G '| * log | G' |) ==> ở đây vì | G '| = O (| G | * log log n / log n) ta có thể thấy thừa số (log log n).
  3. Tính toán SSSP cho từng phần: một lần nữa vì chúng ta có phần O (| G '|) và chúng ta có thể tính toán SSSP cho tất cả các phần trong thời gian | n / logn | * | log n / log logn * log (logn / log log n).
  4. cập nhật trọng số, phần này có thể được thực hiện trong O (n). để biết thêm chi tiết ghi chú bài giảng này là tốt.

Nhưng quan điểm của tôi là, ở đây chúng ta chọn phép chia có kích thước là O (log n / (log log n)). Nếu chúng ta chọn các phép chia khác như O (log n / (log log n) ^ 2) có thể chạy nhanh hơn và mang lại kết quả khác. Ý tôi là, trong nhiều trường hợp (như trong thuật toán xấp xỉ hoặc thuật toán ngẫu nhiên, hoặc thuật toán như SSSP ở trên), khi chúng ta lặp lại một cái gì đó (bài toán con, giải pháp khả thi, ...), chúng ta chọn số lần lặp tương ứng với thương mại của nó chúng ta có (thời gian / không gian / độ phức tạp của thuật toán / hệ số không đổi của thuật toán, ...). Vì vậy, có thể chúng ta thấy nhiều thứ phức tạp hơn "log log n" trong các thuật toán làm việc thực tế.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.