Easy!
題目描述:
給定一個非負索引 k,其中 k ≤ 33,返回楊輝三角的第 k 行。

在楊輝三角中,每個數是它左上方和右上方的數的和。
示例:
輸入: 3 輸出: [1,3,3,1]
進階:
你可以優化你的算法到 O(k) 空間復雜度嗎?
解題思路:
楊輝三角想必大家並不陌生,應該最早出現在初高中的數學中,其實就是二項式系數的一種寫法。
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1
楊輝三角形第n層(頂層稱第0層,第1行,第n層即第n+1行,此處n為包含0在內的自然數)正好對應於二項式
展開的系數。例如第二層1 2 1是冪指數為2的二項式
展開形式
的系數。
楊輝三角主要有下列五條性質:
- 楊輝三角以正整數構成,數字左右對稱,每行由1開始逐漸變大,然后變小,回到1。
- 第
行的數字個數為
個。 - 第
行的第
個數字為組合數
。 - 第
行數字和為
。 - 除每行最左側與最右側的數字以外,每個數字等於它的左上方與右上方兩個數字之和(也就是說,第
行第
個數字等於第
行的第
個數字與第
個數字的和)。這是因為有組合恆等式:
。可用此性質寫出整個楊輝三角形。
由於題目有額外限制條件,程序只能使用O(k)的額外空間,那么這樣就不能把每行都算出來,而是要用其他的方法,。最先考慮用的是第三條性質,算出每個組合數來生成第n行系數,代碼如下:
C++ 解法一:
1 /** 2 * NOT Correct! 3 */ 4 class Solution { 5 public: 6 vector<int> getRow(int rowIndex) { 7 vector<int> out; 8 if (rowIndex < 0) return out; 9 10 for (int i = 0; i <= rowIndex; ++i) { 11 if ( i == 0 || i == rowIndex) 12 out.push_back(1); 13 else 14 out.push_back (computeCnk(rowIndex, i)); 15 } 16 return out; 17 } 18 19 int computeCnk(int n, int k) { 20 if (k > n) return 0; 21 else if (k > n/2) k = n - k; 22 int numerator = 1, denomator = 1; 23 for (int i = 0; i < k; ++i) { 24 numerator *= n - i; 25 denomator *= k - i; 26 } 27 if (denomator != 0) return numerator/denomator; 28 else return 0; 29 } 30 };
本地調試輸出前十行,沒啥問題,拿到OJ上測試,程序在第18行跪了,中間有個系數不正確。那么問題出在哪了呢,仔細找找,原來出在計算組合數那里,由於算組合數時需要算連乘,而整形數int的數值范圍只有-32768到32768之間,那么一旦n值過大,連乘肯定無法計算。而喪心病狂的OJ肯定會測試到成百上千行,所以這個方法不行。那么我們再來考慮利用第五條性質,除了第一個和最后一個數字之外,其他的數字都是上一行左右兩個值之和。那么我們只需要兩個for循環,除了第一個數為1之外,后面的數都是上一次循環的數值加上它前面位置的數值之和,不停地更新每一個位置的值,便可以得到第n行的數字。
C++ 解法二:
1 class Solution { 2 public: 3 vector<int> getRow(int rowIndex) { 4 vector<int> out; 5 if (rowIndex < 0) return out; 6 7 out.assign(rowIndex + 1, 0); 8 for (int i = 0; i <= rowIndex; ++i) { 9 if ( i == 0) { 10 out[0] = 1; 11 continue; 12 } 13 for (int j = rowIndex; j >= 1; --j) { 14 out[j] = out[j] + out[j-1]; 15 } 16 } 17 return out; 18 } 19 };
