原文https://www.zhangman523.cn/420.html
楊輝三角 的算法實(shí)現(xiàn)
楊輝三角形是排列成三角形的一系列數(shù)字。 在楊輝三角形中,每一行的最左邊和最右邊的數(shù)字總是 1。 對于其余的每個(gè)數(shù)字都是前一行中直接位于它上面的兩個(gè)數(shù)字之和。
下面給出一個(gè)5行的楊輝三角:
yanghuiTrangle
基本情況
可以看到,每行的最左邊和最右邊的數(shù)字是基本情況,在這個(gè)問題中,它總是等于 1。
因此,我們可以將基本情況定義如下:
f(i,j) = 1 where j=1 or j=i
遞推關(guān)系
讓我們從楊輝三角形內(nèi)的遞推關(guān)系開始。
首先,我們定義一個(gè)函數(shù) f(i, j)它將會(huì)返回楊輝三角形第 i 行、第 j 列的數(shù)字。
我們可以用下面的公式來表示這一遞推關(guān)系:
f(i,j)=f(i?1,j?1)+f(i?1,j)
java 實(shí)現(xiàn)
給定一個(gè)非負(fù)整數(shù) numRows,生成楊輝三角的前 numRows 行。
示例:
輸入: 5
輸出:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
方法一 迭代實(shí)現(xiàn)
public List<List<Integer> generateTrangle(int numRows){
List<List<Integer>> list = new ArrayList<>();
for(int i=0;i<numRows;i++){
List<Integer> subList = new ArrayList<>();
list.add(subList);
for(int j=0;j<i+1;j++){
f(j==i||j==0){//每行的最左邊和最右邊的數(shù)字都是1
subList.add(1);
}else{
//遞推關(guān)系
subList.add((list.get(i-1).get(j-1)+list.get(i-1).get(j)));
}
}
}
return list;
}
方法二 遞歸實(shí)現(xiàn)
public List<List<Integer>> generateTriangleByRecursive(int numRow) {
List<List<Integer>> list = new ArrayList<>();
for (int i = 0; i < numRow; i++) {
List<Integer> subList = new ArrayList<>();
for (int j = 0; j < i + 1; j++) {
subList.add(generate_Triangle_by_recursive(i, j));
}
list.add(subList);
}
return list;
}
private int generate_Triangle_by_recursive(int i, int j) {
int result;
if (j == 0 || j == i) {
result = 1;
} else {
result =
(generate_Triangle_by_recursive(i - 1, j - 1) + generate_Triangle_by_recursive(
i - 1, j));
}
return result;
}
在上面的例子中,您可能已經(jīng)注意到遞歸解決方案可能會(huì)導(dǎo)致一些重復(fù)的計(jì)算,例如,我們重復(fù)計(jì)算相同的中間數(shù)以獲得最后一行中的數(shù)字。 舉例說明,為了得到 f(5, 3) 的結(jié)果,我們在 f(4, 2) 和 f(4, 3) 的調(diào)用中計(jì)算了 f(3, 2) 兩次。下面我們優(yōu)化遞歸算法
方法三 遞歸+記憶化
public List<List<Integer>> generateTriangleByRecursive(int numRow) {
List<List<Integer>> list = new ArrayList<>();
Map<Integer, Map<Integer, Integer>> cacheMap = new HashMap<>();
for (int i = 0; i < numRow; i++) {
List<Integer> subList = new ArrayList<>();
for (int j = 0; j < i + 1; j++) {
subList.add(generate_Triangle_by_recursive(i, j, cacheMap));
}
list.add(subList);
}
return list;
}
private int generate_Triangle_by_recursive(int i, int j,
Map<Integer, Map<Integer, Integer>> cacheMap) {
if (cacheMap.containsKey(i) && cacheMap.get(i).containsKey(j)) {
return cacheMap.get(i).get(j);
}
int result;
if (j == 0 || j == i) {
result = 1;
} else {
result =
(generate_Triangle_by_recursive(i - 1, j - 1, cacheMap) + generate_Triangle_by_recursive(
i - 1, j, cacheMap));
}
if (!cacheMap.containsKey(i)) {
Map<Integer, Integer> map = new HashMap<>();
cacheMap.put(i, map);
}
cacheMap.get(i).put(j, result);
return result;
}
拓展算法
給定一個(gè)非負(fù)索引 k,其中 k ≤ 33,返回楊輝三角的第 k 行。
示例:
輸入: 3
輸出: [1,3,3,1]
public List<Integer> getRow(int rowIndex) {
List<List<Integer>> list = new ArrayList<>();
for(int i=0;i<rowIndex+1;i++){
List<Integer> subList = new ArrayList<>();
list.add(subList);
for(int j=0;j<i+1;j++){
if(j==i||j==0){//first and end
subList.add(1);
}else{
subList.add((list.get(i-1).get(j-1)+list.get(i-1).get(j)));
}
}
}
return list.get(rowIndex);
}