天氣這麼好,你一點也不想在教室裡待上一個小時。你有些不情願地走進教室,發現黑板上畫著一個形狀奇特、卻令人莫名感到滿足的三角形。在等數學老師來的時候,你不禁注意到這個三角形有幾個規律:最外側的值全都是 1,每一列都比前一列多一個值,而且整個三角形左右對稱。真奇怪!
坐下沒多久,老師就走進教室,解釋說這個三角形就是著名的巴斯卡三角形。
接下來的一小時裡,老師揭開了一些藏在這個三角形裡的奇妙事物:
老師懇切地請你和同學們去查查其他用途,並向你保證還有更多更多喔!就在這時,下課鐘聲響了。你這才發現,過去這一個小時,你完全沉浸在認識巴斯卡三角形的世界裡。你迅速從包包裡拿出筆電,走到外面,準備同時享受陽光_和_巴斯卡三角形的奧妙。
你的任務是輸出巴斯卡三角形的前 N 列。
巴斯卡三角形 是一個由正整數構成的三角形陣列。
在巴斯卡三角形中,每一列的數值個數等於它的列號(列號從 1 開始)。 因此,第 1 列有 1 個數值,第 2 列有 2 個數值,依此類推。
第 1 列(最頂端的那一列)只有 1 個數值:1。
之後每一列的數值,是把上一列中,目前位置正右方與正左方的數字相加而得。
如果上一列在目前位置的左方或右方沒有數值(這只會發生在最左邊和最右邊的位置),就把該位置的數值視為零(等於在相加時「忽略」它)。
來看看巴斯卡三角形的前 5 列吧:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
最頂端的那一列只有 1 個數值,就是 1。
最左邊和最右邊的數值,各自只有一個相鄰位置要考慮,分別是它右方和左方的位置。
由於最頂端的數值是 1,由此可知,所有最左邊和最右邊的數值也都是 1。
其他數值都有兩個位置要考慮。
舉例來說,第 5 列(1 4 6 4 1)中間的數值是 6,因為上一列中它左方和右方的數值分別是 3 和 3:
這個練習的設計是要使用 recursion 來完成,而不是使用迴圈。 遞迴函式是一種會呼叫自身的函式,在解決以自身定義的問題時非常有用。 為了避免無限遞迴(更精確地說,是為了避免堆疊溢位),我們會使用一種稱為「基本情況」的東西。 當達到基本情況時,會回傳一個非遞迴的值,讓前一次的函式呼叫得以解析並回傳它的值,依此類推,一路沿著堆疊往回傳遞,直到第一次的函式呼叫回傳答案。 我們可以寫一個遞迴函式來計算 5!(也就是 5 * 4 * 3 * 2 * 1)的答案,就像這樣:
def factorial(number):
if number <= 1: # base case
return 1
return number * factorial(number - 1) # recursive case
print(factorial(5)) # returns 120
最後要注意的是,Python 限制了遞迴呼叫的次數(預設為 1000 次),而且不會對尾端遞迴進行最佳化。
有時候我們必須引發例外。 當你這麼做時,一定要附上有意義的錯誤訊息,指出錯誤的來源是什麼。 這讓你的程式碼更容易閱讀,也對除錯有相當大的幫助。 如果你知道錯誤來源會是某一種類型,可以選擇引發其中一種內建錯誤類型,但仍然要附上有意義的訊息。
這個練習要求你在rows()函式收到負數時,使用 raise 敘述「拋出」多個ValueErrors。
只有當你同時raise這個exception並附上訊息時,測試才會通過。
若要引發帶有訊息的ValueError,請把訊息寫成exception類型的引數:
# if the rows function is passed a negative number.
raise ValueError("number of rows is negative")