Zadano mi to pytanie podczas rozmowy kwalifikacyjnej i chciałbym wiedzieć, jak inni by to rozwiązali. Najbardziej mi się podoba Java, ale rozwiązania w innych językach są mile widziane.
Biorąc pod uwagę tablicę liczb,
nums
zwróć tablicę liczbproducts
, gdzieproducts[i]
jest iloczyn wszystkichnums[j], j != i
.Input : [1, 2, 3, 4, 5] Output: [(2*3*4*5), (1*3*4*5), (1*2*4*5), (1*2*3*5), (1*2*3*4)] = [120, 60, 40, 30, 24]
Musisz to zrobić
O(N)
bez użycia podziału.
[interview-questions]
szukam tego tagu. Czy masz link, jeśli go znalazłeś?Odpowiedzi:
Wyjaśnienie metody wieloskładnikowych środków smarnych jest następujące: Sztuką jest skonstruowanie tablic (w przypadku 4 elementów)
Oba mogą być wykonane w O (n), zaczynając odpowiednio od lewej i prawej krawędzi.
Następnie pomnożenie elementu dwóch tablic przez element daje wymagany wynik
Mój kod wyglądałby mniej więcej tak:
Jeśli musisz być O (1) w kosmosie, możesz to zrobić (co jest mniej jasne IMHO)
źródło
v_i=0
jedynym niezerowym wpisem w wyniku jest i-ty element. Podejrzewam jednak, że dodanie przepustki w celu wykrycia i zliczenia elementów zerowych pogorszyłoby przejrzystość rozwiązania i prawdopodobnie nie przyniosłoby żadnego rzeczywistego wzrostu wydajności w większości przypadków ..Oto mała funkcja rekurencyjna (w C ++) do wykonania modyfikacji na miejscu. Wymaga jednak O (n) dodatkowej przestrzeni (na stosie). Zakładając, że tablica jest w a, a N ma długość tablicy, mamy
źródło
num[N-1]
; następnie w drodze powrotnej oblicza drugą część mnożenia, która jest następnie używana do modyfikowania tablicy liczb na miejscu.Oto moja próba rozwiązania tego w Javie. Przepraszamy za niestandardowe formatowanie, ale kod ma wiele powielania i jest to najlepsze, co mogę zrobić, aby był czytelny.
Niezmiennikami pętli są
pi = nums[0] * nums[1] *.. nums[i-1]
ipj = nums[N-1] * nums[N-2] *.. nums[j+1]
.i
Część po lewej stronie jest „prefix” logika, aj
część po prawej stronie jest „sufiks” logika.Jednowarstwowa rekurencyjna
Jasmeet dał (piękne!) Rekurencyjne rozwiązanie; Zamieniłem go w tę (ohydną!) Jednowierszową Javę. Dokonuje modyfikacji na miejscu , z
O(N)
tymczasowym miejscem na stosie.źródło
Tłumaczenie rozwiązania Michaela Andersona na Haskell:
źródło
Podstępne obchodzenie zasady „bez podziałów”:
źródło
Oto proste i czyste rozwiązanie o złożoności O (N):
źródło
C ++, O (n):
źródło
Na)
źródło
Oto moje rozwiązanie we współczesnym języku C ++. Wykorzystuje
std::transform
i jest dość łatwy do zapamiętania.Kod online (wandbox).
źródło
To jest O (n ^ 2), ale f # jest bardzo piękne:
źródło
Prekalkuluj iloczyn liczb po lewej i po prawej stronie każdego elementu. Dla każdego elementu pożądana wartość jest iloczynem produktów jego sąsiadów.
Wynik:
(AKTUALIZACJA: teraz przyglądam się bliżej, używa tej samej metody, co Michael Anderson, Daniel Migowski i polygenelubricants powyżej)
źródło
Zdradliwy:
Użyj następujących opcji:
Tak, jestem pewien, że przegapiłem trochę i-1 zamiast i, ale to jest sposób na rozwiązanie tego.
źródło
Istnieje również wartość nieoptymalna dla O (N ^ (3/2)) rozwiązanie . Jest to jednak dość interesujące.
Najpierw należy wstępnie przetworzyć każdą częściową wielokrotność wielkości N ^ 0,5 (odbywa się to w złożoności czasowej O (N)). Następnie obliczenia dla wielokrotności pozostałych liczb dla każdej liczby można wykonać w czasie 2 * O (N ^ 0,5) (dlaczego? Ponieważ wystarczy tylko wielokrotność ostatnich elementów innych ((N ^ 0,5) - 1) liczb, i pomnóż wynik przez ((N ^ 0,5) - 1) liczby należące do grupy bieżącej liczby). Robiąc to dla każdej liczby, można uzyskać czas O (N ^ (3/2)).
Przykład:
4 6 7 2 3 1 9 5 8
wyniki częściowe: 4 * 6 * 7 = 168 2 * 3 * 1 = 6 9 * 5 * 8 = 360
Aby obliczyć wartość 3, należy pomnożyć wartości pozostałych grup 168 * 360, a następnie przez 2 * 1.
źródło
To rozwiązanie, które wymyśliłem, i znalazłem tak jasne, co myślisz !?
źródło
arr = [1, 2, 3, 4, 5] prod = [] produkuj (arr, prod, 0) drukuj prod
źródło
Aby uzupełnić, oto kod w Scali:
Spowoduje to wydrukowanie następujących elementów:
Program odfiltruje bieżący element (_! = Elem); i pomnóż nową listę za pomocą metody replaceLeft. Myślę, że będzie to O (n), jeśli użyjesz widoku Scala lub Iteratora do leniwej ewaluacji.
źródło
Na podstawie odpowiedzi Billza - przepraszam, nie mogę komentować, ale tutaj jest wersja Scala, która poprawnie obsługuje zduplikowane elementy na liście i prawdopodobnie jest O (n):
zwroty:
źródło
Dodając tutaj moje rozwiązanie JavaScript, ponieważ nie znalazłem nikogo, kto by to sugerował. Co należy podzielić, z wyjątkiem tego, ile razy można wyodrębnić liczbę z innej liczby? Przeszedłem obliczanie iloczynu całej tablicy, a następnie iterowanie każdego elementu i odejmowanie bieżącego elementu do zera:
źródło
Używam do C #:
źródło
Możemy najpierw wykluczyć
nums[j]
(gdziej != i
) z listy, a następnie uzyskać iloczyn reszty; Poniżej znajduje siępython way
rozwiązać zagadkę:źródło
Cóż, to rozwiązanie można uznać za C / C ++. Powiedzmy, że mamy tablicę „a” zawierającą n elementów, takich jak [n], wówczas pseudo kod będzie taki jak poniżej.
źródło
Jeszcze jedno rozwiązanie, korzystanie z podziału. z dwukrotnym przejściem. Pomnóż wszystkie elementy, a następnie zacznij dzielić je przez każdy element.
źródło
źródło
Oto mój kod:
źródło
Oto nieco funkcjonalny przykład z użyciem C #:
Nie jestem do końca pewien, czy jest to O (n), z powodu pół-rekurencji utworzonych Funcs, ale moje testy wydają się wskazywać, że jest to O (n) w czasie.
źródło
// To jest rozwiązanie rekurencyjne w Javie // Wywoływane jako wynikające z głównego produktu (a, 1,0);
źródło
Świetne rozwiązanie dzięki środowisku wykonawczemu O (n):
Utwórz końcową tablicę „wynik” dla elementu i,
źródło
źródło
Oto kolejna prosta koncepcja, która rozwiązuje problem
O(N)
.źródło
Mam rozwiązanie o złożoności
O(n)
przestrzennej iO(n^2)
czasowej przedstawione poniżej,źródło