問題描述:
給定一個非負索引 k,其中 k ≤ 33,返回楊輝三角的第 k 行。
在楊輝三角中,每個數是它左上方和右上方的數的和。
示例:
輸入: 3 輸出: [1,3,3,1]
進階:
你可以優化你的算法到 O(k) 空間複雜度嗎?
基本思路:
一開始我的想法就是利用楊輝三角形和排列組合公式相結合。
爲了存儲我的結果我確實需要O(k)的空間。
但是這樣超出了long long的範圍。(算階乘的時候signed integer overflow了,其實完全沒有必要算到這麼大)
於是考慮時間換空間的做法。
(附signed integer overflow的代碼)
class Solution {
public:
long long C(int m, int n) { // m > n
long long up = 1;
long long down = 1;
for (int i = 0; i < n; ++i) {
up *= (m - i);
down *= (i + 1);
}
return up / down;
}
vector<int> getRow(int rowIndex) {
vector<int> res;
for (int i = 0; i <= rowIndex; ++i) {
res.push_back(C(rowIndex, i));
}
return res;
}
};
注意到可以使用滾動數組的思想。
即每一層遍歷的時候還是使用同樣的數組,但是要經過一定的技巧使我們要用到的元素不會被提前覆蓋掉。
觀察得如果我們從後往前覆蓋數組,之前必須的元素就不會被覆蓋掉。
和以上算法的對比就在於我們不得不一層一層地計算得到。
AC代碼:
class Solution {
public:
vector<int> getRow(int rowIndex) {
// rowIndex + 1個0
vector<int> row(rowIndex + 1, 0);
row[0] = 1;
for (int i = 1; i <= rowIndex; ++i) {
for (int j = i; j >= 1; --j)
row[j] = row[j] + row[j - 1];
}
return row;
}
};
其他經驗:
- 使用滾動數組的思想重複利用空間。
- 注意滾動數組中覆蓋的順序,不要讓我們需要使用到的元素被提前覆蓋了。
- 做稍微大一點數字的乘法的時候注意signed integer overflow的錯誤。