杨辉三角,也叫贾宪三角,帕斯卡三角。最早出现于北宋时期,贾宪首先使用“贾宪三角”进行高次开方运算。后来南宋杨辉进行辑录出书,帕斯卡是迟于杨辉三四百年才发现这一规律,叫法上看个人习惯,我习惯称之为杨辉三角。
杨辉三角前几行示图:
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
根据示图我们很容易看出来杨辉三角的一些规律
性质:
每一行的第一个元素和最后一个元素都是 1
每一行除了首尾元素,其他元素都是其上方两元素之和
第 n 行有 n 个元素(行号从 1 开始)
每行元素都是对称的,逐渐变大再逐渐变小
很明显,杨辉三角形每一层的数字跟二项式系数有很亲密的关系。
这个题最讨厌的不仅是要输出前 n 行,还要塞进一个 list 数组里面。毕竟题目是以算法的形式呈现,不能直接打印输出。
思路: 每一行除了首尾元素,其他元素都是其上方两元素之和,抓住这一点就好办了。然后利用 for 循环造出每一行的数字。
代码:
class Solution { public List<List<Integer>> generate(int numRows) { List<List<Integer>> triangle = new ArrayList<>(); for (int i = 0; i < numRows; i++) { List<Integer> list = new ArrayList<>(); for (int j = 0; j <= i; j++) { if (j == 0 || j == i) { list.add(1); } else { list.add(triangle.get(i - 1).get(j - 1) + triangle.get(i - 1).get(j)); } } triangle.add(list); } return triangle; } }
上面最终返回的结果是一个数组,要想真的输出一个等腰三角形的杨辉三角该怎么办,请看下面讲解。
有了上面的讲解,输出杨辉三角的每一行的值是比较简单的,输出整个杨辉三角并且以等腰三角形的形式输出就比较难了,因为你要控制空格数。
代码1:
1 public class YanghuiTriangleExample { 2 3 public static void main(String[] args) { 4 int rows = 10; 5 6 for(int i =0;i<rows;i++) { 7 int number = 1; 8 //打印空格字符串 9 System.out.format("%"+(rows-i)*2+"s",""); 10 for(int j=0;j<=i;j++) { 11 System.out.format("%4d",number); 12 number = number * (i - j) / (j + 1); 13 } 14 System.out.println(); 15 } 16 } 17 } /** * 获取杨辉三角的指定行 * 直接使用组合公式C(n,i) = n!/(i!*(n-i)!) * 则第(i+1)项是第i项的倍数=(n-i)/(i+1); */
原文:https://www.cnblogs.com/JumperMan/p/6759422.html
上面这个代码不能说看不懂吧,那是看的一脸懵逼。后来才发现是涉及到数学知识,不明白的请看里面的注释。
代码2:
边生成边打印
public static void main(String[] args) { //假定输出前5行 int row = 5; int[][] array = new int[row][row]; for (int i = 0; i < row; i++) { for (int j = 0; j < row - i; j++) { System.out.print(" "); } for (int j = 0; j <= i; j++) { if (j == 0 || j == i) { array[i][j] = 1; } else { array[i][j] = array[i - 1][j - 1] + array[i - 1][j]; } System.out.print(array[i][j] + " "); } System.out.println(); } }
先生成数组,再全部打印
public static void main(String[] args) { //假定输出前6行 int row = 6; int[][] array = new int[row][row]; for (int i = 0; i < row; i++) { for (int j = 0; j <= i; j++) { if (j == 0 || j == i) { array[i][j] = 1; } else { array[i][j] = array[i - 1][j - 1] + array[i - 1][j]; } } } // 等腰输出处理 for (int i = 0; i < row; i++) { int num = row - i;// 这里的num只是控制与左边界限的距离 for (int j = 0; j <= num; j++) { System.out.print(" "); } for (int k = 0; k <= i; k++) { System.out.print(array[i][k] + " "); } System.out.println(); } }
上面代码也比较简单,把握好循环次数就好,包括那些空格的输出。
搞明白等腰的打印原理,这个就更好理解了。原理都是一样的,直接上代码。
代码:
public static void main(String[] args) { //假定输出前6行 int row = 6; int[][] array = new int[row][row]; for (int i = 0; i < row; i++) { for (int j = 0; j <= i; j++) { if (j == 0 || j == i) { array[i][j] = 1; } else { array[i][j] = array[i - 1][j - 1] + array[i - 1][j]; } } } // 等腰输出处理 for (int i = 0; i < row; i++) { for (int k = 0; k <= i; k++) { System.out.print(array[i][k] + " "); } System.out.println(); } }
没啥可说的,原理都一样,思路也一样。注意看清楚示例就行了,因为题目中是从第 0 行算起。
个人代码:
class Solution { public List<Integer> getRow(int rowIndex) { List<Integer> list = new ArrayList<>(); int[][] array = new int[rowIndex+1][rowIndex+1]; for (int i = 0; i < rowIndex+1; i++) { for (int j = 0; j <= i; j++) { if (j == 0 || j == i) { array[i][j] = 1; } else { array[i][j] = array[i - 1][j - 1] + array[i - 1][j]; } } } for (Integer i : array[rowIndex]) { list.add(i); } return list; } }
优化:
因为我们每次用到的都是上一行的数据,所以可以使用滚动数组的思想优化数组空间,滚动数组只用存储一行数据,并且实时更新
class Solution { public List<Integer> getRow(int rowIndex) { List<Integer> array = new ArrayList<>(); for (int i = 0; i <= rowIndex; ++i) { List<Integer> curArray = new ArrayList<>(); for (int j = 0; j <= i; ++j) { if (j == 0 || j == i) { curArray.add(1); } else { curArray.add(array.get(j - 1) + array.get(j)); } } array = curArray; } return array; } }
高级做法:
public List<Integer> getRow(int rowIndex) { List<Integer> res = new ArrayList<>(rowIndex + 1); long cur = 1; for (int i = 0; i <= rowIndex; i++) { res.add((int) cur); cur = cur * (rowIndex-i)/(i+1); } return res; } 这里可能有点不好理解,主要就是运用了组合数的数学知识 * 直接使用组合公式C(n,i) = n!/(i!*(n-i)!) * 则第(i+1)项是第i项的倍数=(n-i)/(i+1);
到此,杨辉三角的相关内容就全部讲完了,难度不大,重点是掌握思路方法,这样才能灵活运用。