手把手教你打印杨辉三角
杨辉三角介绍
首先我们先看一下杨辉三角长什么样子
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
......
分析
不难发现,观察后可以得出以下结论: 1.两边都是数字"1" 2.从第三行开始,除了两边的数字"1"之外的数字都是由"肩膀上"的数字相加得到的。
对于一些对算法不太熟悉的人,如果直接去打印,可能就比较困难,所以我们不妨拆开几步来做。
第一步:打印数字都是"0"的三角形
这是比较简单的,第一行是1个数字,第二行是2个数字,第三行是3个数字,以此类推,我们可以归纳得到这样一个规律:第n行有n个数字。于是很容易我们就可以写出以下代码:
public class Main {
public static void main(String[] args) throws Exception {
List<List<Integer>> list = new Main().generate(5);
System.out.println(list);
}
public List<List<Integer>> generate(int numRows) {
if (numRows == 0) {
return new ArrayList<>();
}
List<List<Integer>> linkedList = new LinkedList<>();
//行数
for (int i = 1; i <= numRows; i++) {
List<Integer> list = new LinkedList<>();
//列数
for (int j = 0; j < i; j++) {
list.add(0);
}
linkedList.add(list);
}
return linkedList;
}
调用main方法我们可以在控制台看到以下输出:
[[0], [0, 0], [0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0, 0]]
这里已经可以看出我们获得了一个都是"0"的三角形了!只是打印出来不好看,所以我们再写一个方法,遍历一下这个集合,打印得更好看一点。没什么技术含量,可以照抄,代码如下:
public static void printGenerate(List<List<Integer>> list){
for (int i = 0; i < list.size(); i++) {
for (int j = 0; j < list.size() - i; j++) {
//打印每一行前面的空格
System.out.print(" ");
}
List<Integer> integers = list.get(i);
for (Integer integer : integers) {
//后面的数字,再加上一个空格
System.out.print(integer + " ");
}
//换行
System.out.println();
}
}
然后运行一下,我们就可以看到一个很漂亮的三角形。但是这只是第一步。
0
0 0
0 0 0
0 0 0 0
0 0 0 0 0
第二步:把边上的数字"0"换成数字"1"
这个其实很简单,只需要把每一列的第一个和最后一个换成1,其他的不变即可。代码如下:
public List<List<Integer>> generate(int numRows) {
if (numRows == 0) {
return new ArrayList<>();
}
List<List<Integer>> linkedList = new LinkedList<>();
for (int i = 1; i <= numRows; i++) {
List<Integer> list = new LinkedList<>();
for (int j = 0; j < i; j++) {
//判断每一列的第一个或者最后一个
if(j == 0 || j == i-1){
//数字为1
list.add(1);
}else {
//其他列保持不变,还是0
list.add(0);
}
}
linkedList.add(list);
}
return linkedList;
}
于是我们就可以打印出这样子的三角形:
1
1 1
1 0 1
1 0 0 1
1 0 0 0 1
第三步:"0"都改成"肩膀"的两数之和
通过下面的规律,分析问题:
[1], 第1行 0 <--对应的索引值
[1,1], 第2行 0 1
[1,2,1], 第3行 0 1 2
[1,3,3,1], 第4行 0 1 2 3
[1,4,6,4,1] 第5行 0 1 2 3 4
第三行的"2"是当前集合索引是[1]的值,是由第二行(上一个集合)索引是[0]的值"1"和索引是[1]的值"1"相加得到的。 第四行的第1个"3"是当前集合索引是[1]的值,是由第三行(上一个集合)索引是[0]的值"1"和索引是[1]的值"2"相加得到的。第2个"3"是当前集合索引是[2]的值,是由第三行(上一个集合)索引是[1]的值和索引是[2]的值相加得到的。 以此类推,我们可以得到这样一个结论: 除了首位和末尾的值以外,第n行的索引值为[ j ]的值是由第n-1行的索引值为[ j-1 ]和[ j ]相加得到。
所以我们可以判断从第3行开始,获取上一行的集合,然后除了首位和末尾的数值外(在第二步已经做了处理了),其他的数值都是上一行索引值为[ j-1 ]和[ j ]的值相加而成的。
public List<List<Integer>> generate(int numRows) {
if (numRows == 0) {
return new ArrayList<>();
}
List<List<Integer>> linkedList = new LinkedList<>();
List<Integer> preList = null;
for (int i = 1; i <= numRows; i++) {
List<Integer> list = new LinkedList<>();
if (i >= 3) {
//大于或等于三行则获取上一行的集合
preList = linkedList.get(i - 2);
}
for (int j = 0; j < i; j++) {
if (j == 0 || j == i - 1)
//首位和末尾的数值都是1
list.add(1);
else {
//非首位,非末尾的情况
if (preList != null) {
//数值是由上一行索引值为[j-1]和索引值为[j]相加得到的
list.add(preList.get(j - 1) + preList.get(j));
}
}
}
linkedList.add(list);
}
return linkedList;
}
于是就写完了,我们可以打印出来看看结果:
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
如果输入的行数比较多,数字打印出来不太美观,但是问题不大,比如以下这样:
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 9 36 84 126 126 84 36 9 1
能力有限,如果有什么错误或者不当之处,请大家批评指正,一起学习交流!
- SYNPROXY:最廉价的抗DoS攻击方案
- 如何使用AndroidStudio将开源项目library发布到jcenter
- Android Studio 使用Gradle多渠道打包
- 某些浏览器中因cookie设置HttpOnly标志引起的安全问题
- 偷懒新姿势,打造属于RecyclerView的万能适配器Adapter和ViewHolder
- 科普哈希长度扩展攻击(Hash Length Extension Attacks)
- 分析 WordPress 3.8.2 修復的cookie偽造漏洞
- 技术宅打造全能美剧播放器
- 判断是否支持Heartbeat的NSE脚本
- [原创]Fluent NHibernate之旅二--Entity Mapping
- [原创]Fluent NHibernate之旅(三)-- 继承
- Web应用手工渗透测试——用SQLMap进行SQL盲注测试
- IIS4\IIS5 CGI环境块伪造0day漏洞
- [原创]Fluent NHibernate之旅(四)-- 关系(上)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- ClickHouse 数据导入实战:Kafka 篇
- pipeAsyncFunctions
- 【python-leetcode287-循环排序】寻找重复的数
- 聊聊claudb的list command
- 【python-leetcode448-循环排序】找到所有数组中消失的数字
- input/change/composition/keydown事件详解
- isSameDate
- 【python-leetcode57-区间合并】插入区间
- 【python-leetcode56-区间合并】合并区间
- 【python-leetcode876-快慢指针】链表的中间节点
- vuejs之springboot+vue+element-ui之分页显示相关信息
- vuejs之vue和springboot后端进行通信
- vuejs之springboot+vue+element-ui之添加信息
- vuejs之使用axios发送http请求
- vuejs小例子之记事本