Chocolate Distribution Problem
Masz kilka paczek czekoladek, a packets[i] to liczba czekoladek w paczce i. Każdy z m uczniów dostaje dokładnie jedną paczkę, więc rozdajesz m różnych paczek. Wybierz je tak, aby różnica między największą a najmniejszą z rozdanych paczek była jak najmniejsza.
Napisz funkcję o nazwie minDifference, która zwraca tę najmniejszą możliwą różnicę.
Funkcja
- packetsinteger-array
- liczba czekoladek w każdej paczce
- minteger
- liczba uczniów, z których każdy otrzymuje jedną paczkę
- Zwracainteger
- najmniejsza możliwa różnica między największą a najmniejszą paczką, które zostały rozdane
Ograniczenia
2 ≤ m ≤ packets.length ≤ 1041 ≤ packets[i] ≤ 105- Dwie paczki mogą zawierać taką samą liczbę czekoladek.
Przykłady
- Wejście
- packets = [9, 3, 15, 7, 11, 4]m = 3
- Wyjście
- 4
- Wyjaśnienie
- Po posortowaniu paczki mają wartości 3, 4, 7, 9, 11 i 15. Zarówno 3, 4, 7, jak i 7, 9, 11 dają różnicę
4i żadne trzy paczki nie są bliżej siebie.
- Wejście
- packets = [20, 5, 18, 6, 19]m = 2
- Wyjście
- 1
- Wyjaśnienie
- 5 i 6 różnią się o 1, podobnie jak 18 i 19 oraz 19 i 20. Żadne dwa pakiety nie są równe, więc żadna para nie może osiągnąć wyniku lepszego niż 1.
- Wejście
- packets = [8, 1, 5]m = 3
- Wyjście
- 7
- Wyjaśnienie
- Są trzej uczniowie i trzy paczki, więc każda paczka zostaje rozdana, a różnica wynosi
8 - 1 = 7.
Podpowiedzi
Otwieraj je po kolei. Każda zdradza trochę więcej.
Załóżmy, że znasz już najmniejszą paczkę, którą rozdasz. Które inne paczki powinny do niej pasować?
Gdy najmniejsza paczka jest już ustalona, przydziel
m-1paczek, które następują po niej w kolejności według rozmiaru: każda większa paczka tylko zwiększa różnicę. W posortowanej kolejności te paczki leżą obok siebie.Posortuj pakiety. Każdy ciąg
msąsiadujących pakietów tworzy okno, którego różnica to ostatni pakiet minus pierwszy. Przesuwaj okno od lewej do prawej i zachowuj najmniejszą różnicę.
Rozwiązanie
Sprawdzanie każdej grupy m pakietów trwa zdecydowanie za długo. Najlepszy wybór to zawsze m pakietów leżących obok siebie po posortowaniu pakietów. Wystarczy więc posortować je raz, a odpowiedzią będzie najmniejsza różnica w dowolnym oknie m sąsiadujących pakietów, którą można znaleźć w jednym przebiegu.
Napraw najmniejszą paczkę
Poprawne, ale nie kończy się na największych testach
Intuicja
Ustal najmniejszą paczkę, którą rozdajesz: low. Aby największa paczka była jak najmniejsza, wybierz m-1 najmniejszych paczek, które mają co najmniej low. Różnica to wtedy m-ta najmniejsza paczka spośród tych o rozmiarze co najmniej low minus low. Wypróbuj każdą paczkę jako low, pomiń te, dla których jest mniej niż m paczek o rozmiarze równym temu lub większym, i zachowaj najmniejszą różnicę.
Każdy z n wyborów filtruje i sortuje do n paczek: O(n² log n). Przy n = 10^4 różnych rozmiarach same sortowania wymagają około 6 × 10^8 porównań.
Algorytm
- Ustaw
bestna wartość, której żadna odpowiedź nie może przekroczyć. - Dla każdego pakietu
lowzbierz wszystkie pakiety zawierające co najmniejlowczekoladek i posortuj je. - Jeśli jest ich co najmniej
m, różnica międzym-tym najmniejszym alowjest kandydatem. - Zachowaj najmniejszego kandydata w
besti zwróć go.
def minDifference(packets, m):
best = max(packets) - min(packets) # no gap can be wider than this
for low in packets:
# The packets that could go out alongside low, smallest first (low is one of them).
bigger = sorted(x for x in packets if x >= low)
if len(bigger) >= m:
best = min(best, bigger[m - 1] - low)
return bestPosortuj i przesuń okno zawierające m pakietów
Intuicja
W uporządkowanym ciągu okno sizes[i..i+m-1] ma najmniejszy pakiet na początku, a największy na końcu, więc różnica wynosi sizes[i+m-1] - sizes[i].
Najlepszy wybór zawsze może być oknem. Jeśli wybór pomija pakiet leżący między najmniejszym a największym, zamień największy pakiet na ten pominięty. Najmniejszy pozostaje bez zmian, a największy może być tylko mniejszy, więc różnica nigdy nie wzrośnie. Powtarzaj, aż nie pozostanie żadna luka.
W pierwszym przykładzie okna złożone z trzech elementów dają 4, 5, 4 i 6, więc odpowiedź to 4. Sortowanie ma złożoność O(n log n), a przesuwanie okna O(n).
Algorytm
- Posortuj pakiety rosnąco w
sizes. - Ustaw
bestnasizes[m-1] - sizes[0], czyli pierwsze okno. - Dla każdego początku
iod 1 don-mporównajsizes[i+m-1] - sizes[i]zbesti zachowaj mniejszą wartość. - Zwróć
best.
def minDifference(packets, m):
sizes = sorted(packets)
best = sizes[m - 1] - sizes[0]
# The window sizes[i..i+m-1] holds m packets; its first is the smallest, its last the largest.
for i in range(1, len(sizes) - m + 1):
best = min(best, sizes[i + m - 1] - sizes[i])
return best
Pułapki i przypadki brzegowe
- Kończenie okna na
i+mzamiast nai+m-1, co obejmujem+1pakietów. - Zatrzymywanie się o jedno okno za wcześnie. Początkowe indeksy biegną od 0 do
n-mwłącznie. Dla[1, 10, 20, 21]przym = 2pętla z warunkiemi < n-mpomija jedyną różnicę równą 1. - Pominięcie sortowania. W
[9, 3, 15, 7, 11, 4]pierwsze trzy pakiety różnią się o 12, podczas gdy odpowiedź wynosi 4. - Mierzenie tylko pierwszego okna.
mnajmniejszych pakietów to jeden z możliwych wyborów, ale najlepsza grupa może zaczynać się w dowolnym miejscu. - Sortowanie liczb jako tekstu. W JavaScript
sort()bez komparatora umieszcza100000przed9.
Najczęstsze pytania3
Jaka jest złożoność czasowa problemu z rozdzielaniem czekolady?
Sortowanie zajmuje O(n log n), a przesuwanie okna obejmującego m pakietów zajmuje O(n), więc łączna złożoność wynosi O(n log n). Dodatkowe miejsce wynosi O(n) na posortowaną kopię albo O(1) poza samym sortowaniem, jeśli sortujesz dane wejściowe w miejscu.
Czy problem dystrybucji czekoladek jest problemem z oknem przesuwnym?
Tak, okno o stałym rozmiarze przesuwające się po posortowanych pakietach. W przeciwieństwie do okna z sumą bieżącą nie ma nic do aktualizowania podczas jego przesuwania: różnica dla każdego okna to wynik odejmowania pierwszego pakietu od ostatniego.
Czy problem z rozdzielaniem czekolady można rozwiązać bez sortowania?
Rozmiary są tutaj co najwyżej równe 10^5, więc sortowanie przez zliczanie porządkuje je w czasie O(n + 10^5) i obowiązuje to samo rozumowanie. Przy nieograniczonych rozmiarach same porównania nie pozwalają osiągnąć lepszego czasu niż O(n log n): dla m = 2 odpowiedź wynosi 0 dokładnie wtedy, gdy dwa pakiety są równe, a wykrycie duplikatu wymaga w najgorszym przypadku tylu porównań.
Podobne zadania
Zadania oparte na tych samych pomysłach. Rozwiązanie dwóch lub trzech utrwala schemat.
def minDifference(packets, m):
# Napisz kod tutajTest #1
Test #2
Test #3
Argumenty
packets = [9, 3, 15, 7, 11, 4] m = 3
Oczekiwany wynik
4