trong thời gian O (n): Tìm phần tử lớn nhất trong tập hợp so sánh không mang tính bắc cầu


21

Tiêu đề nêu câu hỏi.

Chúng tôi có đầu vào như một danh sách các yếu tố, mà chúng tôi có thể so sánh (xác định cái nào là lớn nhất ). Không có yếu tố nào có thể bằng nhau.

Những điểm chính:

  1. So sánh không mang tính bắc cầu (nghĩ rằng kéo giấy đá): điều này có thể đúng: A> B, B> C, C> A (lưu ý đây không phải là đầu vào hợp lệ vì không có câu trả lời hợp lệ ở đây, tôi chỉ mô tả những gì " so sánh không bắc cầu "có nghĩa là)
  2. Mỗi mảng đầu vào sẽ được đảm bảo có câu trả lời
  3. lớn nhất có nghĩa là phần tử phải lớn hơn mọi phần tử khác
  4. Thuộc tính converse giữ tức là A> B ngụ ý rằng B <A

Thí dụ:

Input: [A,B,C,D]
A > B, B > C, C > A
D > A, D > B, D > C
Output: D

Tôi không thể tìm ra cách để làm điều này trong thời gian O (n), giải pháp tốt nhất của tôi là O (n ^ 2).

Tôi bị mắc kẹt trên mọi phương pháp vì thực tế là để chắc chắn có câu trả lời, yếu tố này cần được so sánh rõ ràng với mọi yếu tố khác, để chứng minh đó thực sự là câu trả lời (vì so sánh không mang tính bắc cầu).

Điều này quy định việc sử dụng một đống, sắp xếp, vv


8
Không rõ "yếu tố vĩ đại nhất" sẽ được định nghĩa như thế nào? Ví dụ, phần tử nào là lớn nhất nếu ? Bạn có bất kỳ quy tắc so sánh khác? A>B,B>C,C>A
fade2black

6
Tôi không thể tưởng tượng làm thế nào chúng ta sẽ chọn phần tử lớn nhất trong một tập hợp mà ít nhất là một phần. Xin vui lòng xem định nghĩa của các yếu tố lớn nhất và ít nhất. Thiếu các quy tắc chuyển đổi ra một phần trật tự.
fade2black

3
@ fade2black Tại sao bạn liên kết tôi với một định nghĩa khác về "vĩ đại nhất". Tôi nói rõ ràng định nghĩa lớn nhất cho bối cảnh của câu hỏi này. Phương tiện lớn nhất, yếu tố này lớn hơn mọi yếu tố khác. Không có phần tử nào bằng nhau. Đó là tất cả để có nó. Điều này không rõ ràng?
James Wierzba

2
Ví dụ cuối cùng của bạn với A, B, C, D sẽ hữu ích để hiểu câu hỏi của bạn nếu bạn đưa nó vào OP của bạn.
fade2black

3
Một thành viên của nhóm biên dịch C # đã từng hỏi điều này như một câu hỏi phỏng vấn; nó có liên quan vì trong C #, thuật toán phân giải quá tải phải chọn thành viên tốt nhất duy nhất của một tập hợp có mối quan hệ "tốt hơn" thường, nhưng không nhất thiết phải là bắc cầu. (Hoặc đưa ra một câu trả lời phù hợp nếu không có thành viên tốt nhất duy nhất như vậy; có thể có mối quan hệ thuật toán tuyến tính.
Eric Lippert

Câu trả lời:


38

Thuật toán tiêu chuẩn để tìm tối đa vẫn hoạt động. Bắt đầu với và đi qua các yếu tố, nếu bạn thấy một giá trị lớn hơn, cập nhật tối đa là giá trị đó. Lý do điều này hoạt động là mọi yếu tố bạn bỏ qua nhỏ hơn ít nhất một yếu tố và do đó không thể là tối đa.a1

Để rõ ràng, theo "thuật toán tiêu chuẩn", ý tôi là như sau:

max <- a_1
for i=2 to n
   if a_i > max
      max <- a_i
output max

Để đầy đủ, tôi sẽ thảo luận ở đây các vấn đề được nêu trong các ý kiến. Các thiết lập trong các cuộc thảo luận ở trên là tìm một người họ hàng tối đa cho một mối quan hệ đối xứng chống , nơi một i là tối đa nếu cho tất cả j i chúng tôi có một i > một j . Thuật toán trên hoạt động theo giả định rằng tồn tại tối đa, tuy nhiên nếu không biết điều này, người ta có thể sử dụng nó để xác minh sự tồn tại của mức tối đa (kiểm tra xem phần tử được trả về có thực sự lớn hơn tất cả các phần tử khác hay không, điều này được đề cập trong nhận xét của Chi và trong câu trả lời của Ilmari Karonen).<aijiai>aj

Nếu không nhất thiết là đối xứng, thì thuật toán trên không thành công (như Emil đã đề cập trong các bình luận). Nếu < là một mối quan hệ tùy ý (nghĩa là chúng ta đang thư giãn cả tính đối xứng và tính đối xứng), thì không khó để chỉ ra rằng việc tìm kiếm tối đa trong thời gian tuyến tính là không thể. Biểu thị bằng # một i số lần một tôi tham gia vào một truy vấn, chúng tôi xác định một mối quan hệ thù địch trong một cách mà tối đa không thể tiết lộ mà không đủ các truy vấn. Căn cứ vào truy vấn một i > ? a j , trả lời a i > a j nếu # a i<<#aiaiai>?ajai>aj a i < a j nếu không. Nếu số lượng truy vấn là o ( n 2 ) , thì mức tối đa chưa được nhìn thấy và nó có thể được đặt thành một trong các thành phần trong tập hợp.#ai<n1ai<ajo(n2)


1
@JamesWierzba (tôi nghĩ) anh ta chỉ có nghĩa là một yếu tố "bị bỏ qua" là một yếu tố không lớn hơn mức tối đa hiện tại của bạn. Xem xét thuật toán tiêu chuẩn: bạn kiểm tra từng giá trị trong danh sách của bạn so với mức tối đa hiện tại. Bạn đã nói có một yếu tố lớn nhất trong mỗi danh sách. Tại một số điểm, bạn sẽ so sánh với giá trị tối đa hiện tại của mình và vì nó lớn hơn, giá trị đó trở thành mức tối đa mới của bạn. Vì giá trị này lớn hơn mọi thứ khác trong danh sách, bạn sẽ không bao giờ tìm thấy yếu tố nào lớn hơn và giá trị lớn nhất của bạn sẽ không bị thay thế. Sau khi nso sánh, tối đa hiện tại của bạn phải là câu trả lời
Lord Farquaad

1
Được chỉnh sửa cho rõ ràng, thuật toán này không giả định tính siêu việt. Nếu bạn thấy khó tin, hãy làm theo các chi tiết của bằng chứng chính xác (giả sử cho mục đích mâu thuẫn rằng giá trị trả về không phải là tối đa và sử dụng ý tưởng từ đoạn đầu tiên).
Ariel

7
Điều này phụ thuộc vào giả định 2 trong câu hỏi: luôn có một mức tối đa trong mảng. Nếu đây không phải là trường hợp, maxchỉ có thể là tối đa của một phân khúc. Tuy nhiên, ngay cả khi không có giả định 2, người ta có thể tìm thấy mức tối đa dự kiến, và sau đó xác minh nó trên toàn bộ mảng bằng cách quét lần thứ hai, trong giới hạn O (n).
chi

7
Câu trả lời này giả định rằng B > A không thể giữ cùng một lúc. Theo như tôi có thể thấy, điều này không được loại trừ trong câu hỏi. A>BB>A
Emil Jeřábek hỗ trợ Monica

4
@ oconnor0 Điều đó không tuân theo. Đối với một ví dụ cụ thể, giả sử A> B, A> C, B> A và C> B. Khi đó A lớn hơn bất kỳ phần tử nào khác trong tập hợp (và là phần tử duy nhất có thuộc tính này), nhưng nếu các phần tử là gặp phải theo thứ tự A, B, C, thuật toán sẽ xuất C.
Emil Jeřábek hỗ trợ Monica

24

Như Ariel lưu ý , thuật toán tìm tối đa tiêu chuẩn được đưa ra dưới đây:

def find_maximum(a):
    m = a[0]
    for x in a:
        if x > m: m = x
    return m

trong thực tế sẽ làm việc mà không sửa đổi miễn là:

  • bất kỳ cặp yếu tố nào cũng có thể được so sánh, và
  • đầu vào được đảm bảo chứa một phần tử tối đa, tức là một phần tử lớn hơn từng cặp so với bất kỳ phần tử nào khác trong đầu vào.

(Giả định đầu tiên ở trên thực sự có thể được nới lỏng, thậm chí không cần phải sửa đổi thuật toán, miễn là chúng tôi giả định rằng phần tử tối đa có thể so sánh với mọi phần tử khác và x > yluôn luôn sai nếu các phần tử xykhông thể so sánh được.)

Cụ thể, yêu cầu của bạn rằng:

[Chắc chắn] để chắc chắn về một câu trả lời, yếu tố này cần được so sánh rõ ràng với mọi yếu tố khác (vì so sánh không mang tính bắc cầu).

là không đúng theo các giả định được đưa ra ở trên. Trong thực tế, để chứng minh rằng thuật toán ở trên sẽ luôn tìm thấy phần tử tối đa, đủ để quan sát rằng:

  1. vì vòng lặp lặp trên tất cả các phần tử đầu vào, tại một số lần lặp xsẽ là phần tử tối đa;
  2. vì phần tử cực đại lớn hơn từng cặp so với mọi phần tử khác, nên theo sau, ở phần lặp đó, msẽ là phần tử cực đại; và
  3. vì không có phần tử nào khác có thể được ghép đôi lớn hơn phần tử cực đại, nên phần tử theo sau msẽ không thay đổi trên bất kỳ lần lặp tiếp theo nào.

Do đó, ở cuối vòng lặp, msẽ luôn là phần tử tối đa, nếu đầu vào chứa một.


Thi thiên Nếu đầu vào không nhất thiết phải luôn chứa một phần tử tối đa, thì việc xác minh thực tế đó thực sự sẽ yêu cầu kiểm tra câu trả lời của ứng viên đối với mọi yếu tố khác để xác minh rằng nó thực sự là tối đa. Tuy nhiên, chúng ta vẫn có thể làm điều đó trong thời gian O ( n ) sau khi chạy thuật toán tìm tối đa ở trên:

def find_maximum_if_any(a):
    # step 1: find the maximum, if one exists
    m = a[0]
    for x in a:
        if x > m: m = x

    # step 2: verify that the element we found is indeed maximal
    for x in a:
        if x > m: return None  # the input contains no maximal element
    return m  # yes, m is a maximal element

(Tôi giả sử ở đây rằng mối quan hệ >là không phản xạ, tức là không có yếu tố nào có thể lớn hơn chính nó. Nếu không nhất thiết phải như vậy, thì nên so sánh x > mở bước 2 x ≠ m and x > m, trong đó biểu thị so sánh nhận dạng. Hoặc chúng ta có thể áp dụng tối ưu hóa lưu ý dưới đây.)

Để chứng minh tính đúng đắn của biến thể thuật toán này, hãy xem xét hai trường hợp có thể xảy ra:

  • Nếu đầu vào chứa một phần tử tối đa, thì bước 1 sẽ tìm thấy nó (như được hiển thị ở trên) và bước 2 sẽ xác nhận nó.
  • Nếu đầu vào không chứa phần tử tối đa, thì bước 1 sẽ chọn một số phần tử tùy ý là m. Không quan trọng đó là yếu tố nào, vì trong mọi trường hợp, nó sẽ không tối đa, và do đó bước 2 sẽ phát hiện ra và trả về None.

Nếu chúng ta lưu trữ các chỉ số mtrong mảng đầu vào a, chúng ta có thể thực sự bước tối ưu hóa 2 để chỉ kiểm tra những yếu tố mà đến trước mtrong a, vì bất kỳ yếu tố sau đã được so sánh với mở bước 1. Nhưng tối ưu hóa này không làm thay đổi mức độ phức tạp thời gian tiệm cận của thuật toán, vẫn là O ( n ).


3
Trong thực tế, OP bỏ qua nhiều chi tiết. Ví dụ, không có gì được nói về tính phản xạ của mối quan hệ, và vì vậy nếu nó không phản xạ thì if x > m:không xác định được.
fade2black

4

O(n)

Nếu bạn xem qua danh sách so sánh các yếu tố của mình, bất kỳ yếu tố nào "mất" so sánh có thể bị loại bỏ ngay lập tức vì để trở thành lớn nhất, nó phải lớn hơn TẤT CẢ các yếu tố khác để mất một lần loại bỏ nó.

n1 sự so sánh và kết thúc với những yếu tố lớn nhất là kết quả của sự so sánh cuối cùng của bạn, bằng cách loại bỏ một kẻ thất bại mỗi và mọi lúc.

Giải pháp này được kích hoạt bởi một sự tinh tế: "Không có yếu tố nào có thể bằng" kết hợp với thực tế là sẽ luôn có một yếu tố lớn nhất. Nếu chúng ta lập bản đồ chiến thắng các mối quan hệ dưới dạng biểu đồ có hướng, rõ ràng chúng ta có thể đạt được yếu tố lớn nhất chỉ bằng cách theo dõi các chiến thắng.


1
" Đồ thị theo hướng chu kỳ " là mô hình sai: thay vào đó nên là " giải đấu ". Chu kỳ được cho phép và điều quan trọng là mọi cạnh đều tồn tại theo một hướng chính xác.
Peter Taylor

@PeterTaylor bạn hoàn toàn đúng, tôi chỉ nghĩ về những chiến thắng dẫn đến yếu tố 'vĩ đại nhất', những chiến thắng khác ít liên quan hơn nhưng có thể đi qua con đường khám phá những điều vĩ đại nhất để bạn có thể ' t được giảm giá
Danikov

3

Tôi giả định rằng mối quan hệ đối xứng cho ít nhất một yếu tố duy nhất (đảm bảo sự tồn tại của yếu tố lớn nhất), nếu không thì nhiệm vụ là không thể. Nếu tất cả các phần tử trong tập hữu hạn có thể so sánh được thì quy trình tìm tối đa thông thường sẽ hoạt động.

Nếu một số yếu tố không thể so sánh thì quy trình sau sẽ hoạt động.

max = nil
For i=1 to n
   if max is nil then
      max = a[i]
   if max and a[i] are not comparable then
      max = nil
   else if max < a[i] then
      max = a[i]
End

Một,B,C,D

Một>B,B>C,C>Một
D>Một,D>B,D>C
như trong bài viết của bạn.

Ban đầu. tối đa
tôi= =1: tối đa= =Một
tôi= =2: tối đa= =Một (kể từ khi Một>B)
tôi= =3: tối đa= =C (kể từ khi Một<C)
tôi= =4: max=D (since D>C)

This algorithm works since if m>a (or a<m) for all a then m is the greatest. If m<a for some element a then m cannot be the greatest. Similarly, if a and m are not comparable then they both cannot be the greatest. This procedure would work even if all elements are comparable.


I don't think the first else if is needed. It cannit be triggered if max is the maximum, and if the maximum has not yet been encountered it doesn't matter what the value of max is.
rici

Yes, that is the first one. The other one is the second one :)
rici

You mean leave ifs without elses? It is just a habit: with elses we do not even compare. :)
fade2black

1
Wouldn't it be simpler to just initialize max to any element of the list and, inside the loop, do if max and a[i] are comparable and max < a[i] then max = a[i] (where the first part of the condition could be omitted if we assume that trying to compare two incomparable elements always yields false)?
Ilmari Karonen

1
@badallen the OP assumes that there is always the greatest element. In your example there is no greatest element.
fade2black

2

As an addition to Ariel's answer about the concerns raised by Emil Jeřábek: If we allow A<B and B<A then there is no O(n) algorithm:

Assume you have elements A1...An. Your algorithm will in each step query Ai<Aj for some pair i and j. No matter in which order you query them, there is always a relation where you have to query all relations before finding the maximum. The reason for this is best described by assuming you have an adversary who can change the problem while your algorithm is running.

(Note that the argument is independent of what the algorithm actually does with the information he gets about the elements, since it explains that he cannot know that an element is maximal before making n2 queries.)

For most of the algorithm the adversary will make sure to always return true for Ai<Aj until your last query for a given j. Note that you cannot know that one given element is maximal until you compared it to all other elements. Only for the last element for which you finish all relations the adversary will return true for the last element as well.

The resulting relation will always be such that there is some j0 for which Ai<Aj0i and for all other j there will be some ij such that Ai<Ajiij and we will not have Aij<Aj. The adversary chooses j0 and the ijs depending on your algorithm.

I hope this is somewhat understandable. Feel free to ask in comments or edit.

The basic idea is that you cannot gather any information about the remaining elements from the ones you already know if you allow a completely arbitrary relation.

The argument still works if we disallow A<A. We will only save n queries that way and still need n2n.


1

I'm going to cheat and call the number of A > B entries n and you need to look at every entry at least once.

That way you can loop over just the entries and remove the element that is less than the other from the set of possible solutions. With a hashset or similar this is possible in O(n)

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.