Jakie jest najlepsze podejście do obliczania największego czynnika pierwszego z liczby?
Myślę, że najbardziej wydajne byłyby następujące:
- Znajdź najniższą liczbę pierwszą, która dzieli czysto
- Sprawdź, czy wynik podziału jest liczbą pierwszą
- Jeśli nie, znajdź następny najniższy
- Idź do 2.
Opieram to założenie na tym, że łatwiej jest obliczyć małe czynniki pierwsze. Czy to w porządku? Jakie inne podejścia powinienem rozważyć?
Edycja: Teraz zdałem sobie sprawę, że moje podejście jest daremne, jeśli w grze występują więcej niż 2 czynniki pierwsze, ponieważ krok 2 kończy się niepowodzeniem, gdy wynik jest iloczynem dwóch innych liczb pierwszych, dlatego potrzebny jest algorytm rekurencyjny.
Edytuj ponownie: A teraz zdałem sobie sprawę, że to nadal działa, ponieważ ostatnia znaleziona liczba pierwsza musi być najwyższa, dlatego każde dalsze testowanie wyniku niepierwotnego z kroku 2 spowoduje mniejszą liczbę pierwszą.
źródło
1.
znajdź dowolną liczbę, która wyraźnie dzieli (dla i = 2 do int (sqr (num)))2.
podziel przez tę liczbę (num = num / i) i powtarzaj się, dopóki nic nie zostanie znalezione w 1. interwał3.
num jest największym czynnikiemOdpowiedzi:
W rzeczywistości istnieje kilka bardziej efektywnych sposobów znajdowania czynników o dużych liczbach (w przypadku mniejszych podział prób działa dość dobrze).
Jedną z metod, która jest bardzo szybka, jeśli liczba wejściowa ma dwa czynniki bardzo zbliżone do pierwiastka kwadratowego, jest znana jako faktoryzacja Fermata . Wykorzystuje tożsamość N = (a + b) (a - b) = a ^ 2 - b ^ 2 i jest łatwy do zrozumienia i wdrożenia. Niestety ogólnie nie jest bardzo szybki.
Najbardziej znaną metodą faktorowania liczb o długości do 100 cyfr jest sito kwadratowe . Jako bonus część algorytmu można łatwo wykonać przy przetwarzaniu równoległym.
Jeszcze innym algorytmem, o którym słyszałem, jest algorytm Rho Pollarda . Nie jest tak wydajny jak sito Quadratic w ogóle, ale wydaje się, że jest łatwiejszy do wdrożenia.
Gdy zdecydujesz, jak podzielić liczbę na dwa czynniki, oto najszybszy algorytm, jaki mogę wymyślić, aby znaleźć największy czynnik pierwszy z liczby:
Utwórz kolejkę priorytetową, która początkowo przechowuje sam numer. Podczas każdej iteracji usuwasz najwyższą liczbę z kolejki i próbujesz podzielić ją na dwa czynniki (oczywiście nie dopuszczając, aby 1 był jednym z tych czynników). Jeśli ten krok się nie powiedzie, liczba jest pierwsza i masz odpowiedź! W przeciwnym razie dodaj dwa czynniki do kolejki i powtórz.
źródło
Oto najlepszy algorytm, jaki znam (w Pythonie)
Powyższa metoda działa w
O(n)
najgorszym przypadku (gdy wejście jest liczbą pierwszą).EDYCJA:
Poniżej znajduje się
O(sqrt(n))
wersja, jak sugerowano w komentarzu. Oto kod, jeszcze raz.źródło
O(sqrt(n))
najgorszym przypadku” - Nie, wpada wO(n)
najgorszym przypadku (np. kiedyn
jest pierwsza).Moja odpowiedź oparta jest na Tryptyku , ale bardzo się poprawia. Opiera się na fakcie, że poza 2 i 3 wszystkie liczby pierwsze mają postać 6n-1 lub 6n + 1.
Niedawno napisałem artykuł na blogu wyjaśniający, jak działa ten algorytm.
Zaryzykowałbym, że metoda, w której nie ma potrzeby badania pierwotności (i bez konstrukcji sita), działałaby szybciej niż ta, która wykorzystuje te. W takim przypadku jest to prawdopodobnie najszybszy algorytm.
źródło
while (multOfSix - 1 <= n)
Kod JavaScript:
Przykład użycia:
Oto przykład kodu :
źródło
Podobne do odpowiedzi @Triptych, ale także inne. W tym przykładzie nie użyto listy ani słownika. Kod jest napisany w języku Ruby
źródło
Wszystkie liczby można wyrazić jako iloczyn liczb pierwszych, np .:
Możesz je znaleźć, zaczynając od 2 i po prostu kontynuując dzielenie, aż wynik nie będzie wielokrotnością liczby:
korzystając z tej metody nie musisz w rzeczywistości obliczać liczb pierwszych: wszystkie będą liczbami pierwszymi, w oparciu o fakt, że już uwzględniłeś liczbę jak najwięcej ze wszystkimi poprzednimi liczbami.
źródło
currFactor = 3513642
celu wiemy, że 12345678987667 jest liczbą pierwszą i powinniśmy go zwrócić jako odpowiedź. Zamiast tego ten kod będzie kontynuował wyliczanie do samego 12345678987667. To 3,533,642x wolniej niż to konieczne.źródło
while
pętla przejdzie przezi
wartości2,2,2,2,2,2,2,2,2,2,2,2, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5
. Wszystkie 60 iteracji. Jednak dla 10 (^ 12 + 39) będzie (10 ^ 12 + 38) iteracjii=2,3,4,5,6,...,10^12+39
. Nawet jeśli 10 ^ 10 operacji zajmie jedną sekundę, 10 ^ 12 zajmie 100 sekund. Ale tak naprawdę potrzebne są tylko 10 ^ 6 iteracji, a jeśli 10 ^ 10 operacji zajmie sekundę, 10 ^ 6 zajmie 1/10 000 tysięcznej sekundy.long n = 2*1000000000039L
? Czy działa tak szybko, jak powinien? (możesz też uprościć kod za pomocąreturn;
instrukcji?). (jeśli chcesz, żebym przestał cię szturchać, po prostu to powiedz;))Najprostszym rozwiązaniem jest para wzajemnie rekurencyjnych funkcji.
Pierwsza funkcja generuje wszystkie liczby pierwsze:
Druga funkcja zwraca pierwsze liczby danej liczby
n
w porządku rosnącym.n
.Największym czynnikiem pierwszym
n
jest ostatnia liczba podana przez drugą funkcję.Ten algorytm wymaga leniwej listy lub języka (lub struktury danych) z semantyką wywołania na żądanie .
Dla wyjaśnienia, oto jedna (nieefektywna) implementacja powyższego w Haskell:
Przyspieszenie tego jest po prostu sprytniejsze w wykrywaniu liczb pierwszych i / lub czynników
n
, ale algorytm pozostaje ten sam.źródło
Istnieje kilka testów modulo, które są zbędne, ponieważ n nigdy nie można podzielić przez 6, jeśli wszystkie czynniki 2 i 3 zostaną usunięte. Można zezwolić tylko na liczby pierwsze dla i, co pokazano w kilku innych odpowiedziach tutaj.
Można tutaj właściwie przeplecić sito Eratostenesa:
Zobacz także to pytanie .
źródło
Wiem, że to nie jest szybkie rozwiązanie. Publikowanie jako, miejmy nadzieję, łatwiejsze do zrozumienia powolne rozwiązanie.
źródło
Podejście iteracyjne w języku Python poprzez usunięcie wszystkich liczb pierwszych z liczby
źródło
Korzystam z algorytmu, który nadal dzieli liczbę przez jej aktualny współczynnik Prime.
Moje rozwiązanie w python 3:
Wejście:
10
Wyjście:5
Wejście:
600851475143
Wyjście:6857
źródło
Oto moja próba w c #. Ostatni wydruk jest największym czynnikiem podstawowym liczby. Sprawdziłem i działa.
źródło
źródło
Oblicza największy czynnik pierwszy liczby za pomocą rekurencji w C ++. Działanie kodu wyjaśniono poniżej:
źródło
Oto moje podejście do szybkiego obliczenia największego czynnika pierwszego. Opiera się na fakcie, że zmodyfikowany
x
nie zawiera czynników innych niż podstawowe. Aby to osiągnąć, dzielimy się,x
gdy tylko znajdzie się czynnik. Następnie pozostaje tylko zwrócić największy czynnik. Byłoby to już pierwsze.Kod (Haskell):
źródło
Poniższy algorytm C ++ nie jest najlepszy, ale działa dla liczb poniżej miliarda i jest dość szybki
źródło
Znalazłem to rozwiązanie w Internecie przez „James Wang”
źródło
Czynnik zalania za pomocą sita:
źródło
Wydaje mi się, że krok 2 podanego algorytmu nie będzie aż tak efektywnym podejściem. Nie masz uzasadnionych oczekiwań, że jest to liczba pierwsza.
Również poprzednia odpowiedź sugerująca, że sito Eratostenesa jest całkowicie błędna. Właśnie napisałem dwa programy z współczynnikiem 123456789. Jeden opierał się na Sito, drugi na następujących:
Ta wersja była 90 razy szybsza niż Sito.
Chodzi o to, że we współczesnych procesorach rodzaj operacji ma znacznie mniejsze znaczenie niż liczba operacji, nie wspominając już o tym, że powyższy algorytm może działać w pamięci podręcznej, a sito nie. Sito wykorzystuje wiele operacji wykreślających wszystkie liczby zespolone.
Zauważ też, że moje czynniki podziału podczas ich identyfikacji zmniejszają przestrzeń, którą należy przetestować.
źródło
Najpierw oblicz listę przechowującą liczby pierwsze, np. 2 3 5 7 11 13 ...
Za każdym razem, gdy liczba pierwsza zostanie rozłożona na czynniki pierwsze, użyj implementacji przez tryptyk, ale iterując tę listę liczb pierwszych zamiast liczb całkowitych naturalnych.
źródło
Z Javą:
Dla
int
wartości:Dla
long
wartości:źródło
Prawdopodobnie nie zawsze jest to szybsze, ale bardziej optymistyczne, że znajdujesz duży główny dzielnik:
N
jest twój numerreturn(N)
Sqrt(N)
N is divisible by Prime
takReturn(Prime)
Edycja: W kroku 3 możesz użyć sita Eratostenesa lub sita Atkinsa lub cokolwiek innego, ale samo sito nie znajdzie dla ciebie największego czynnika podstawowego. (Dlatego nie wybrałbym postu SQLMenace jako oficjalnej odpowiedzi ...)
źródło
Myślę, że dobrze byłoby przechowywać gdzieś wszystkie możliwe liczby pierwsze mniejsze niż n i po prostu iterować je, aby znaleźć największy dzielnik. Możesz dostać liczby pierwsze z prime-numbers.org .
Oczywiście zakładam, że twój numer nie jest zbyt duży :)
źródło
Nie najszybszy, ale działa!
źródło
Oto ta sama funkcja @ Tryptyk podana jako generator, która również została nieco uproszczona.
maksymalną liczbę pierwszą można następnie znaleźć za pomocą:
oraz listę czynników znalezionych przy użyciu:
źródło
źródło