Sắp xếp danh sách các chuỗi theo thứ tự từ điển của các chuỗi được sắp xếp


8

Đặt là tập hợp các chuỗi trên bảng chữ cái có tổng số ký hiệu.A{0,,m1}n

Nhiệm vụ của bạn là sắp xếp từng chuỗi bên trong, sau đó sắp xếp các chuỗi kết quả theo thứ tự từ điển. (Thuật toán của bạn không phải vận hành theo cách này.)

Thí dụ:

Đầu vào: 33123 15 1 0 54215 21 12

Đầu ra: 0 1 12 12 12333 12455 15

Tôi tìm thấy một cách để làm điều đó trong thời gian và không gian .O(m+n)O(mn)

Không gian lớn hơn thời gian vì tôi sử dụng một mảng thông minh cho phép bạn tạo một mảng có kích thước và sắp xếp các giá trị ban đầu cho tất cả các ô trong .nO(1)

Tôi đã sử dụng sắp xếp xô để sắp xếp từng chuỗi ( thời gian và không gian) và từ cây để sắp xếp bộ sưu tập ( thời gian và không gian ). nhưng giải pháp của tôi quá phức tạp.O(m+n)AO(m+n)O(mn)

Có ai có giải pháp tốt hơn, với thời gian và ít không gian hơn, hoặc nhanh hơn không?O(m+n)O(m+n)

Giải pháp phải có tính xác định để không có bản đồ băm hoặc các thuật toán thống kê khác


Giải pháp của tôi: Mảng thông minh là một mảng có kích thước mà chúng ta có thể tạo và "khởi tạo" trong :mO(1)

Chúng tôi tạo ra ba mảng kích thước của mà không cần khởi tạo bất kỳ trong số họ và chúng tôi cũng giữ một biến số nguyên duy nhất được gọi là .mC

Mảng đầu tiên chứa dữ liệu. Mảng thứ hai chứa các con trỏ tới một ô trong mảng thứ ba. Mảng thứ ba chứa các con trỏ tới một ô trong mảng thứ hai. chứa số lượng tế bào được khởi tạo cho đến nay.C

Giả sử chúng ta muốn đặt giá trị của ô (giả sử đây là lần đầu tiên chúng ta thực hiện nó trên ô này). Sau đó, chúng ta sẽ đi đến ô trong mảng đầu tiên và đặt nó vào val mong muốn.ii

Bây giờ chúng ta đi đến ô trong mảng thứ hai và đặt nó vào điểm ở mảng thứ ba. Đặt ô trong mảng thứ ba để trỏ đến ô trong mảng thứ hai. Tăng thêm 1.iCCiC

Giả sử chúng ta muốn biết nếu ô là rác (Điều đó có nghĩa là chúng ta chưa đặt bất cứ thứ gì cho nó).j

Chúng ta sẽ đi đến ô trong mảng thứ hai và xem số ô (trong mảng thứ ba) mà ô (trong mảng thứ hai) trỏ đến - chúng ta sẽ gọi nó là .jjk

Nếu thì là rác (vì chúng ta chỉ khởi tạo các ô cho đến nay và không phải là một trong số chúng).k>CjCj

Nếu chúng ta sẽ xem ô nào (trong mảng thứ ba) trỏ đến. Nếu nó không phải thì là rác. Nếu không thì không phải là ráck<Ckjjj

Bằng cách đó, chúng ta có thể biết ở mỗi bước nếu chúng ta khởi tạo ô này và nếu không khởi tạo nó. Vì vậy, chúng tôi đã tạo và "khởi tạo" một mảng có kích thước trong thời gian .mO(1)

Bí quyết chính không phải là khởi tạo toàn bộ mảng khi bắt đầu mà là tìm cách biết những ô nào chúng ta đã khởi tạo cho đến nay và chỉ khởi tạo một ô khi chúng ta "nhìn" vào nó. Trong mô hình RAM, phải mất thời gian để tạo ra một mảng có kích thước bất kỳ mà không khởi tạo nó.O(1)


Một cây từ có thứ tự m là một khái quát của TRIE. Mỗi nút chứa một mảng các con trỏ tới các con trai của nó. Kích thước mảng là . Mỗi nút cũng chứa một bộ đếm để cho biết có bao nhiêu bộ được mô tả bởi nút này.m

Bởi vì chúng ta đang sử dụng các mảng thông minh mỗi lần chúng ta thêm một chữ (một bộ) chỉ mất thời gian và không gian.AO(|A|)O(m|A|)


5
Thời gian không thể nhỏ hơn không gian. Bạn đang gian lận theo một cách nào đó.
Yuval Filmus

Chắc chắn nó có thể. Tạo một mảng ở kích thước n mà không cần thiết lập lại thì phải mất O (1). Điều đó đúng với c và c ++. Sau đó, bạn có thể sử dụng cấu trúc dữ liệu rất đơn giản để theo dõi những ô nào bạn đã sử dụng và đó là rác
Ofer Magen

3
Tôi không quan tâm nhiều đến C và C ++. Chúng tôi thường phân tích các thuật toán theo mô hình máy RAM. Trong mô hình này thời gian không thể nhỏ hơn không gian. Tôi hơi lo lắng rằng mảng thông minh của bạn không thực sự hoạt động trong mỗi lần truy cập. O(1)
Yuval Filmus

1
Mô hình RAM lấy O (1) để xác định một mảng có kích thước n (máy tính chỉ cần xác định các con trỏ bắt đầu và kết thúc). Phải mất O (n) để đặt lại thành số không. C ++ LÀ ngôn ngữ mô hình ram, đó là lý do tại sao tôi đưa ra ví dụ này
Ofer Magen

@YuvalFilmus Time cannot be smaller than spaceđúng. You are cheating in some waykhông tuân theo " time và space": với , - giới hạn trên không gian trông không cần thiết. O(m+n)O(mn)1mnxm+yn+zO(mn)
greybeard

Câu trả lời:


0

Bạn cũng có thể giải quyết điều này trong thời gian và không gian :O(nlogn)O(n)

  • Đầu tiên, sắp xếp từng từ bằng cách sử dụng mergesort. Thời gian chạy này sẽ nhiều nhất là và không gian sử dụng là .O(nlogn)O(n)

  • Sau đó, lưu trữ tất cả các từ trong một trie từ. Thời gian và không gian cho việc này sẽ là , nếu bạn thực hiện từ trie đúng cách. Đặc biệt, tại mỗi nút của bộ ba, bạn nên lưu trữ tập hợp con dưới dạng hashtable (không phải là một mảng). Theo cách này, việc lưu trữ tại một nút tỷ lệ thuận với số lượng trẻ em có và việc tìm kiếm một đứa trẻ có thể được thực hiện trong thời gian . Do đó, thời gian chạy của giai đoạn này là thời gian và không gian .O(n)O(1)O(n)O(n)

  • Cuối cùng, đọc tất cả các từ trong bộ ba. Điều này liên quan đến việc lấy từng hashtable và sắp xếp nội dung của nó, giả sử sử dụng mergesort. Tất cả các bước sắp xếp đó sẽ mất nhiều thời gian nhất là .O(nlogn)

Cấu trúc dữ liệu kết quả có vẻ khá đơn giản. Điều này đặc biệt đơn giản nếu bạn triển khai bằng ngôn ngữ có hỗ trợ tích hợp cho hashmap (ví dụ: Javascript, Python).

Ngoài ra, bạn có thể thay thế hashmap bằng cấu trúc dữ liệu cây nhị phân cân bằng và có thời gian chạy tương tự.


Như một lưu ý chung về "mảng thông minh":

Bạn có thể thay thế việc sử dụng "mảng thông minh" bằng hashtable. Bằng cách đó, bạn sẽ duy trì khả năng đọc và viết (dự kiến). Cụ thể, thay vì đặt , bạn lưu trữ giá trị tại khóa (nghĩa là thêm ánh xạ vào hàm băm). Khi bạn muốn đọc giá trị của , thay vào đó bạn tra cứu trong hashtable và trả lại bất cứ thứ gì bạn tìm thấy ở đó. Theo cách này, việc sử dụng không gian tỷ lệ thuận với số lượng mục khởi tạo trong "mảng thông minh" và mỗi lần truy cập mất thời gian (dự kiến).O(1)A[i]:=vvkkvA[i]iO(1)


Hashtable là các công cụ thống kê và tôi cần một giải pháp xác định. Việc sử dụng sắp xếp hợp nhất là không cần thiết. Bạn có thể sử dụng sắp xếp xô vì đó là các số nguyên trong phạm vi từ 1 đến m và giải nó trong O (n + m)
Ofer Magen

Tuy nhiên, mảng thông minh hoàn toàn mang tính quyết định
Ofer Magen

4
Bạn đã yêu cầu nhanh hơn . nhanh hơn đối với một số tham số - nhưng không phải đối với các tham số khác. Nếu bạn không muốn sử dụng hàm băm, hãy sử dụng cấu trúc dữ liệu cây nhị phân cân bằng, như tôi đã đề xuất trong câu trả lời của mình - đạt được cùng thời gian chạy và giới hạn không gian , và Vì vậy, hoàn toàn xác định. O(n+m)O(nlogn)O(n+m)O(nlogn)O(n)
DW

@OferMagen nếu bộ sưu tập A được biết trước, bạn có thể sử dụng băm hoàn hảo tối thiểu, do đó không có va chạm.
Gerardo Zinno

0

Bạn có thể sắp xếp một tập của chuỗi trên một bảng chữ cái số nguyên kích thước sử dụng một Trie trong thời gian và không gian, nơi là phân biệt tiền tố của .S{0,1,,σ1}σO(dσ)dS

Đây là một giải pháp không sử dụng bảng băm.

Hãy được chiều dài của tiền tố ngắn của chuỗi mà phân biệt nó với các dây khác trong . Tiền tố phân biệt của được định nghĩa là .dssSSSd=sSds

Thuật toán để giải quyết vấn đề sử dụng phương pháp phân chia & chinh phục, đó là RadixSort bắt đầu từ chữ số có nghĩa nhất (char).

1) Tạo xôσ0,1,,σ1

2) Xử lý chuỗi ký tự theo từng ký tự từ đầu và phân phối chúng vào các thùng bằng cách sử dụng CountingSort trong thời gian .σO(1)

3) Lặp lại quy trình trên các thùng chứa nhiều hơn một phần tử bằng cách sử dụng ký tự tiếp theo để sắp xếp chúng.

4) Nối các nhóm từ trái sang phải để có được thứ tự.

Thuật toán này tạo ra một bộ ba -ary, trong đó mỗi nút là một mảng có kích thước và các chuỗi được lưu trữ trong các lá.σσ

Đây là một ví dụ.

Đặt là và .σ5S={410,013,042,111,001,444}

Sau đây là bộ ba được tạo bởi thuật toán: trie

Mỗi chuỗi phát ra một đường dẫn có kích thước trước khi nút trỏ đến được tạo. Mỗi nút trong những con đường mất không gian và thời gian được phân bổ.sO(ds)sO(σ)O(σ)


Sử dụng phương pháp này nhưng thay thế các nút có kích thước bằng các bảng băm có kích thước tỷ lệ với các cạnh đi ra từ nút, bạn có thể làm cho thuật toán chạy trên thời gian trung bình và không gian . σO(d logσ)O(d)
Gerardo Zinno
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.