Steps to Reduce a Number to Zero
Zacznij od nieujemnej liczby całkowitej n i powtarzaj jedną regułę, aż osiągnie 0: jeśli liczba jest parzysta, podziel ją przez 2; jeśli jest nieparzysta, odejmij 1. Każde zastosowanie reguły to jeden krok. Zwróć liczbę kroków.
Funkcja
- ninteger
- liczba początkowa
- Zwracainteger
- liczba kroków, zanim liczba osiągnie 0
Ograniczenia
0 ≤ n ≤ 231 - 1
Przykłady
- Wejście
- n = 14
- Wyjście
- 6
- Wyjaśnienie
- Liczba zmienia się tak:
14 → 7 → 6 → 3 → 2 → 1 → 0: trzy dzielenia przez dwa i trzy odejmowania,6kroków.
- Wejście
- n = 8
- Wyjście
- 4
- Wyjaśnienie
8 → 4 → 2 → 1 → 0. Potęga dwójki jest dzielona na pół trzy razy i wymaga jednego odejmowania na końcu, czyli4kroki.
- Wejście
- n = 123
- Wyjście
- 12
- Wyjaśnienie
123w systemie binarnym to1111011: siedem cyfr i sześć jedynek. Sześć jedynek wymaga sześciu odejmowań, a sześć cyfr poniżej wiodącej jedynki — sześciu dzieleń przez dwa, czyli12kroków.
Pytanie dodatkowe
Załóżmy, że liczbę nieparzystą można również zwiększyć o 1. Jaka jest najmniejsza liczba kroków potrzebna do osiągnięcia 0 i która opcja jest właściwa dla 15?
Podpowiedzi
Otwieraj je po kolei. Każda zdradza trochę więcej.
Ręcznie zastosuj regułę do
14i policz. Ile razy można podzielić przez 2 liczbę 32-bitową?Zapisz liczby w systemie binarnym. Co dzieje się z cyframi przy dzieleniu przez dwa i co się dzieje po odjęciu
1od liczby nieparzystej?Każdy bit 1 kosztuje jedno odejmowanie, a każda cyfra binarna oprócz wiodącej kosztuje jedno dzielenie przez 2. Potraktuj
n == 0osobno.
Rozwiązanie
W systemie binarnym dzielenie przez dwa usuwa ostatnią cyfrę, a odjęcie 1 od liczby nieparzystej zamienia jej ostatnie 1 na 0. Zatem dla n > 0 odpowiedzią jest liczba cyfr binarnych plus liczba jedynek minus jeden. Bezpośrednie wykonywanie tej reguły również jest szybkie: najwyżej 61 kroków.
Uruchom proces
Intuicja
Wykonaj regułę i policz kroki. Dla 14 pętla odwiedza 7, 6, 3, 2, 1 i 0: sześć kroków.
Odejmowanie zawsze zmienia liczbę nieparzystą w parzystą, więc co najmniej co drugi krok jest dzieleniem przez dwa. Liczba mniejsza niż 2^31 jest dzielona przez dwa najwyżej 30 razy, zanim osiągnie 1. Przy jednym odejmowaniu przed każdym dzieleniem przez dwa i jednym na końcu pętla wykona najwyżej 61 iteracji. Dla n = 0 pętla w ogóle się nie wykonuje, a odpowiedź wynosi 0.
Algorytm
- Ustaw
stepsna0. - Dopóki
n > 0: jeślinjest parzyste, ustawnnan / 2, w przeciwnym razie nan-1. - Za każdym razem dodaj
1dosteps. - Zwróć
steps.
def numberOfSteps(n):
steps = 0
while n > 0:
if n % 2 == 0:
n //= 2
else:
n -= 1
steps += 1
return stepsPolicz cyfry binarne
Intuicja
Każdy krok albo usuwa ostatnią cyfrę binarną, albo zamienia końcowe 1 na 0. 14 to 1110: dzielenie przez 2 daje 111, a odejmowanie od 111 daje 110. Każde 1 trzeba usunąć jeden raz, co kosztuje jedno odejmowanie na każde 1. Każdą cyfrę trzeba usunąć, wykonując jedno dzielenie przez 2, z wyjątkiem wiodącej jedynki: gdy zostaje tylko 1, jej odjęcie i tak daje 0. Zatem odpowiedź to length - 1 + ones, a dla 14 wynosi 4 - 1 + 3 = 6.
Java, C, C++, Go, Rust i Swift mają wbudowane operacje zliczania obu wartości (zer wiodących i ustawionych bitów), które na większości procesorów kompilują się do pojedynczych instrukcji. W innych językach odczytuj cyfry za pomocą % 2 w pętli trwającej co najwyżej 31 rund. Najpierw obsłuż n = 0: nie ma ono żadnego bitu 1, który mógłby stanowić podstawę wzoru.
Algorytm
- Jeśli
n == 0, zwróć0. - Znajdź
length, liczbę cyfr binarnychn. - Znajdź
ones, liczbę bitów o wartości 1. - Zwróć
length - 1 + ones.
def numberOfSteps(n):
if n == 0:
return 0
# Every bit below the leading one costs a halving,
# and every 1 bit costs a subtraction.
return n.bit_length() - 1 + bin(n).count("1")
Pułapki i przypadki brzegowe
- Pominięcie
n = 0we wzorze bitowym.length - 1 + onesdaje-1, a liczba zer wiodących dla0może być niezdefiniowana (__builtin_clz(0)w C). - Liczenie dzielenia przez połowę dla wiodącej cyfry.
1zmienia się w0przez odejmowanie, więc8 = 1000wymaga4 - 1 + 1 = 4kroków, a nie5. - Zapisywanie
n = (n-1) / 2dla liczby nieparzystej i liczenie jednego kroku. Ta linijka wykonuje dwa kroki, więc dla14otrzymujemy4zamiast6. - Wykonywanie pętli, dopóki
n > 1. Zatrzymuje się ona przed ostatnim krokiem, który zmienia1w0.
Najczęstsze pytania3
Jaka jest złożoność czasowa redukowania liczby do zera?
Wykonanie procesu zajmuje czas O(log n), ponieważ co najmniej co drugi krok zmniejsza liczbę o połowę: 61 kroków dla n = 2^31 - 1. Liczenie cyfr binarnych za pomocą wbudowanych instrukcji bitowych zajmuje O(1).
Która liczba mniejsza od 2^31 wymaga najwięcej kroków?
2^31 - 1, czyli liczba zapisana w systemie binarnym jako trzydzieści jeden jedynek. Wymaga 31 odejmowań i 30 połowień, łącznie 61 kroków. Żadna mniejsza liczba nie ma jednocześnie tylu cyfr i tylu jedynek.
Dlaczego dzielenie przez dwa jest tym samym co przesunięcie w prawo?
Liczba binarna jest sumą potęg liczby dwa. Dzielenie liczby parzystej przez 2 zmniejsza każdą potęgę o jeden, co przesuwa każdą cyfrę o jedno miejsce w prawo i usuwa końcowe 0. To właśnie robi n >> 1, więc dzielenie przez dwa możesz zapisać na oba sposoby.
Podobne zadania
Zadania oparte na tych samych pomysłach. Rozwiązanie dwóch lub trzech utrwala schemat.
def numberOfSteps(n):
# Wpisz kod tutajTest #1
Test #2
Test #3
Argument
n = 14
Oczekiwany wynik
6