给定一个非负整数 numRows,生成「杨辉三角」的前 numRows 行。
在「杨辉三角」中,每个数是它左上方和右上方的数的和。
【解析】稍微解释一下杨辉三角的定义,其实看动图就非常容易理解杨辉三角的定义了,任意一个数的值是它上一行紧挨着的左边和右边的数字的和,哎呀妈呀好绕…结合动图和我的文字理解一下吧!
示例 1:
输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]
示例 2:
输入: numRows = 1
输出: [[1]]
【解析】“numRows”给的是杨辉三角的行数,numRows = 1 则表示求出杨辉三角第1行,numRows = 3 表示求出杨辉三角前3行。杨辉三角每一行的数字都是固定的。
杨辉三角,是二项式系数在三角形中的一种几何排列。它是中国古代数学的杰出研究成果之一,它把二项式系数图形化,把组合数内在的一些代数性质直观地从图形中体现出来,是一种离散型的数与形的结合。
【解析】这句话直接说明了杨辉三角的意义,其是二项式系数的图形化,简单的说就是用图形的方式去表示二项式系数。啊~数学,真是超级有意思。
杨辉三角具有以下性质:
① 每行数字左右对称,由 1开始逐渐变大再变小,并最终回到 1。
【解析】这条性质十分简单,直接使用观察法就看出来了。
② 第 n行(从 0开始编号)的数字有 n+1 项,前 n 行共有
n ( n + 1 ) 2 \frac {n(n+1)}{2} 2n(n+1)个数。
【解析】继续使用观察法来观察,第0行共有1个数字,第1行共有2个数字,第2行共有3个数字…第n行共有 n+1 个数字。那么前n行一共有多少个数字呢?直接套用等差数列的前n项和就可以了。
③ 第 n行的第 m个数(从 0 开始编号)可以被表示为组合数 C(n,m),记作 C n m C_n^m Cnm, 即为从 n 个不同元素中取 m 个元素的组合数。我们可以用公式来表示它: C n m = n ! m ! ( n − m ) ! C_n^m=\frac{n!}{m!(n-m)!} Cnm=m!(n−m)!n!
【解析】此处n和m有点混的同学可以直接看上图,“n”代表的是某一行,“m”代表的是具体行的某一个数字。
④ 每个数字等于上一行的左右两个数字之和,可用此性质写出整个杨辉三角。即第 n 行的第 i个数等于第 n−1 行的第 i−1 个数和第 i 个数之和。这也是组合数的性质之一,即 C n i = C n − 1 i + C n − 1 i − 1 C_n^i=C_{n−1} ^i+C_{n−1 }^{i−1} Cni=Cn−1i+Cn−1i−1 的展开式(二项式展开)中的各项系数依次对应杨辉三角的第 n 行中的每一项。
【解析】这一条还是画图来解析来的更直观一些。
⑤ 依据性质 4,我们可以一行一行地计算杨辉三角。每当我们计算出第 i 行的值,我们就可以在线性时间复杂度内计算出第 i+1 行的值。
【解析】其实一行一行地算就相当于是递推了,已知第一行,计算出下一行…依次递推就可以了。
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
ret = list()
for i in range(numRows):
row = list()
for j in range(0, i + 1):
if j == 0 or j == i:
row.append(1)
else:
row.append(ret[i - 1][j] + ret[i - 1][j - 1])
ret.append(row)
return ret
作者:力扣官方题解
链接:https://leetcode.cn/problems/pascals-triangle/solutions/510638/yang-hui-san-jiao-by-leetcode-solution-lew9/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【解析】
① 首先初始化了一个列表“ret”,用来存放所有行的数字。
② 每一行的数字也以列表的形式存储,每一行的列表都初始化为row。
③ “i”表示某一行,即第1行, 第2行等等。j 表示特定行的某一个数字。
④ 根据性质①可知,杨辉三角每一行的开始和结尾都是1, 故当
j == 0:表示该行的第一个数字
j == i :表示该行的最后一个数字
时候,直接给列表加1即可。
⑤ 除去每一行的首位元素末位元素直接为1外,其余所有元素根据性质③中的公式来计算即可。ret[i-1] : 定位到存放上一行所有数字的列表;ret[i - 1][j]:定位到第 i-1 行 的 第 j 个元素。同理ret[i - 1][j-1]
时间复杂度:O(numRows2)
【解析】双层for循环,清晰明了。
空间复杂度:O(1)。不考虑返回值的空间占用。
该解法来自Leecode本题的热门题解,十分讨巧所所以也值得一写!如果说法1是老老实实的解法那么法2就是一种十分讨巧的方法,话不多说直接上图!
简单描述一下:每行 =该行的上一行 + 该行上一行向后移动一位。是不是非常神奇呢!高手在民间哈哈哈!在代码层的实现只需要在空余位置补0就可以啦,也就是在每行的首位和末位补0。上图中给补0的位置都标红了。
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
if numRows == 0:
return []
res = [[1]]
while len(res) < numRows:
newline = [a+b for a,b in zip(res[-1]+[0],[0]+res[-1])]
res.append(newline)
return res
作者:陆诚
链接:https://leetcode.cn/problems/pascals-triangle/solutions/53504/qu-qiao-jie-fa-cuo-yi-wei-zai-zhu-ge-xiang-jia-28m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【代码解析】
① 首先对特殊情况做出排除,即:如果numRows = 0,那么直接返回空数组即可。
② 对特殊情况做出排除后,初始化 res 数组为[[1]],按照解法2,至少要给出一行才能递推出其余行。
③ 最巧妙之处莫过于 zip() 函数的使用。zip()函数的使用方法戳这里:Python zip() 函数
④ 还有一巧妙之处就是 res[-1],因为每次生成新的一行仅仅与上一行有关,所以只需要取 res 数组的最后一项,不需要使用额外的计数器!
时间复杂度:O(numRows2)
【分析-来自chatgpt】:生成杨辉三角的过程中,代码需要对每一行的元素进行计算,并且生成的行数与输入的numRows有关。
在循环中,对于每一行(除了第一行),生成新的行需要对前一行的元素进行遍历和计算。每一行的元素个数与行数相等,所以第i行有i个元素。因此,对于生成第i行,需要进行O(i)次计算。
现在考虑整个过程,我们需要生成numRows行的帕斯卡三角形。对于第1行,需要进行O(1)次计算,对于第2行,需要进行O(2)次计算,对于第3行,需要进行O(3)次计算,以此类推,对于第numRows行,需要进行O(numRows)次计算。
因此,生成杨辉三角的总时间复杂度是前n个自然数的和,即O(1 + 2 + 3 + … + numRows)。这是一个等差数列的和,可以用等差数列求和公式来计算:
1 + 2 + 3 + … + numRows = numRows * (numRows + 1) / 2
因此,总的时间复杂度是O(numRows^2)。
空间复杂度:O(numRows2)
【分析-来自chatgpt】
同理空间复杂度。对于第i行,该行有i个元素,因此在res列表中存储第i行需要O(i)的空间。
现在考虑整个过程,我们需要生成numRows行的帕斯卡三角形,且每一行的元素个数与行数相等。因此,整个过程需要O(1 + 2 + 3 + … + numRows)的空间。
类似于计算时间复杂度的方法,O(1 + 2 + 3 + … + numRows)是一个等差数列的和,可以用等差数列求和公式来计算:
1 + 2 + 3 + … + numRows = numRows * (numRows + 1) / 2
因此,整个过程的空间复杂度是O(numRows^2)。