Last digit of a huge number

MirrorTan發表於2019-06-23

這是我在 Codewars 中遇到的一個比較有意思的題目:求一個列表中元素累計乘方的最後一位數。

1 題幹描述

For a given list [x1, x2, x3, ..., xn] compute the last (decimal) digit of x1 ^ (x2 ^ (x3 ^ (... ^ xn))).

E. g.,

last_digit([3, 4, 2]) == 1
because 3 ^ (4 ^ 2) = 3 ^ 16 = 43046721.

Beware: powers grow incredibly fast. For example, 9 ^ (9 ^ 9) has more than 369 millions of digits. lastDigit has to deal with such numbers efficiently.

Corner cases: we assume that 0 ^ 0 = 1 and that lastDigit of an empty list equals to 1.

This kata generalizes Last digit of a large number; you may find useful to solve it beforehand.

原題參見:https://www.codewars.com/kata/5518a860a73e....

簡而言之,就是給定一個列表,求累計乘方的結果的個位數數值。

2 題目分析

對於這類題目,直接硬算顯然是不可能的,題中給出的幾個測試樣例就過不了:

# 樣例
test_data = [
    ([], 1),
    ([0, 0], 1),
    ([0, 0, 0], 0),
    ([1, 2], 1),
    ([3, 4, 5], 1),
    ([4, 3, 6], 4),
    ([7, 6, 21], 1),
    ([12, 30, 21], 6),
    ([2, 2, 2, 0], 4),
    ([937640, 767456, 981242], 0),
    ([123232, 694022, 140249], 6),
    ([499942, 898102, 846073], 6)
]

題幹其實已經給了我們提示,只要累計乘方的個位數值,那麼顯然應該存在某種規律,經過測試後發現,數值的冪次結果的個位數以 4 存在迴圈:

def printer(numbers, numbers_power):
    print(' ', ' '.join(str(power) for power in range(len(numbers_power[0]))))
    for number in numbers:
        print(number, ' '.join(str(result)[-1] for result in numbers_power[number]))

if __name__ == "__main__":
    numbers = list(range(9))
    numbers_power = []
    for number in numbers:
        numbers_power.append([number**power for power in range(13)])
    printer(numbers, numbers_power)

將之儲存為 demo.py 並執行得到如下結果:

$ python3 demo.py
  0 1 2 3 4 5 6 7 8 9 10 11 12
0 1 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 2 4 8 6 2 4 8 6 2 4 8 6
3 1 3 9 7 1 3 9 7 1 3 9 7 1
4 1 4 6 4 6 4 6 4 6 4 6 4 6
5 1 5 5 5 5 5 5 5 5 5 5 5 5
6 1 6 6 6 6 6 6 6 6 6 6 6 6
7 1 7 9 3 1 7 9 3 1 7 9 3 1
8 1 8 4 2 6 8 4 2 6 8 4 2 6
9 1 9 1 9 1 9 1 9 1 9 1 9 1

也即,除 0 次冪意外,x ** n 的個位數意思迴圈:str(x ** n)[-1] == str(x ** (n+4))[-1]!(整數 x 的 n 次冪的個位數值由 x 的個位數值的 n 次冪決定)

在這個題目中,我們將冪次運算的結果作為下一次運算的冪,而根據上一步我們得到冪次運算結果個位數值以 4 為迴圈的結果(0 次冪除外)。將 demo.py 的 printer 函式的最後一行改為:

print(number, ' '.join(str(result % 4) for result in numbers_power[number]))

執行後得到的結果是:

$ python3 demo.py
  0 1 2 3 4 5 6 7 8 9 10 11 12
0 1 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 2 0 0 0 0 0 0 0 0 0 0 0
3 1 3 1 3 1 3 1 3 1 3 1 3 1
4 1 0 0 0 0 0 0 0 0 0 0 0 0
5 1 1 1 1 1 1 1 1 1 1 1 1 1
6 1 2 0 0 0 0 0 0 0 0 0 0 0
7 1 3 1 3 1 3 1 3 1 3 1 3 1
8 1 0 0 0 0 0 0 0 0 0 0 0 0
9 1 1 1 1 1 1 1 1 1 1 1 1 1

我們發現,(x ** n) % 4 穩定迴圈 ~ 0 次冪和 1 次冪除外 ~ 我們可以將大於 4 的冪次結果使用 (x ** n) % 4 + 4 來保持結果的一致性。

3 解決方案

綜上,寫出的程式碼如下:

def last_digit(lst):
    # Your Code Here
    n = 1
    for x in reversed(lst):
        n = x ** (n if n < 4 else n % 4 + 4)
    return n % 10

最後,附上原題網址:https://www.codewars.com/kata/5518a860a73e...

相關文章