這是我在 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