杨辉三角①与②

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 5
输出:
[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
 

思路:动态规划问题,每一行第一个和最后一个元素恒为1,故可以使用双重循环,设置一个List temp,外层循环每次先将该行的首位与末尾置1,然后进入通过内层循环,计算第2位到第numRows-1位的元素的值,即上一行该元素所在列的元素与所在列-1的元素之和,并将求得的值赋给temp,结束外层循环后将其追加至arr列表中,相当于每次将一个列表当做一个元素赋值给初始列表arr。

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        arr = []
        for Row in range(numRows):
            temp = [None for i in range(Row+1)]
            temp[0],temp[-1] = 1, 1
            for num in range(1,len(temp)-1):
                temp[num] = arr[Row-1][num-1] + arr[Row-1][num]
            arr.append(temp)
        return arr

if __name__ == "__main__":
    c = Solution()
    print(c.generate(5))

执行用时 :28 ms, 在所有 Python3 提交中击败了96.16%的用户

内存消耗 :12.7 MB, 在所有 Python3 提交中击败了99.59%的用户

 

class Solution:
    def getRow(self, rowIndex: int) -> List[int]:
        arr = []
        numRows = 34
        for Row in range(numRows):
            temp = [None for i in range(Row+1)]
            temp[0],temp[-1] = 1, 1
            for num in range(1,len(temp)-1):
                temp[num] = arr[Row-1][num-1] + arr[Row-1][num]
            arr.append(temp)
        return arr[rowIndex]

 

 

解法二:

思路:杨辉三角之间是存在规律的,当前一行只比上一行多了一个元素,并且本行元素等于上一行元素往后错一位再逐个相加,

因此我们只要对最后一行单独处理:最后一行首、尾分别添加一个零然后对应位置求和就可以得到新的一行。

微信图片_20191211113539.jpg

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        if numRows == 0: 
            return []
        res = [[1]]
        while len(res) < numRows:
            newRow = [a+b for a, b in zip([0]+res[-1], res[-1]+[0])]
            res.append(newRow)      
        return res


作者:lu-cheng-5

 

 

 

 

杨辉三角②:要求给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 行,加个下标就行,但是效率太低了,这里主要记录一个博主的总结,很全面了

作者:clarkchainer
链接:https://leetcode-cn.com/problems/pascals-triangle-ii/solution/js-yang-hui-san-jiao-ii-972-shi-suan-he-tu-suan-si/

既然已经做到了这道题,你肯定对杨辉三角已经有一个基本的了解了。
从数学的角度上来说,杨辉三角的每一项都对应着(a + b)的n次方展开后每一项的系数。
由于这道题需要得出的是第N行的内容,那么第一反应想到通过通项公式来计算得出每一项填充到数组里就是很自然的事情了。
 

从数学的角度上来说,杨辉三角的每一项都对应着(a + b)的n次方展开后每一项的系数。
由于这道题需要得出的是第N行的内容,那么第一反应想到通过通项公式来计算得出每一项填充到数组里就是很自然的事情了。

1、式算
第n行第k列的值,可以通过通项公式:(n-1)!/(k-1)!(n-k)!计算得到
代码如下:

// 主逻辑
let getRow = function(rowIndex) {
    rowIndex++;
    let resultArr = [];
    for (let i = 1; i < rowIndex + 1; i++) {
        resultArr.push(factorial(rowIndex - 1) / (factorial(i - 1) * factorial(rowIndex - i)));
    }
    return resultArr;
};

// 求阶乘
function factorial(num) {
    if (num < 2) {
        return 1;
    } else {
        return num * factorial(num - 1);
    }
}
完成了式算后,我发现最后的结果却并不是很好——64.14%
(这里还有很多可以优化的空间,甚至大神可以0ms,但是更多是针对数学角度的考虑,就不展开聊了)

2、图算(动态规划)
式算的结果让我有点失望,那么再试试图算。
图算其实就是《118、杨辉三角I》那道题里的做法,通过上一行推导下一行。
直接修改一下上一题的代码,每次覆盖上一行的内容就好

let getRow = function(rowIndex) {
    if (rowIndex === 0) {
        return [1];
    }
    if (rowIndex === 1) {
        return [1,1];
    }
    let resultArr = [1,1];
    for (let i = 2; i < rowIndex + 1; i++) {
        let tempArr = [];
        for (let j = 0; j <= i; j++) {
            tempArr.push((j === 0 ? 0 : resultArr[j - 1]) + (j === i ? 0 : resultArr[j]))
        }
        resultArr = tempArr;
    }
    return resultArr;
};
91.37%,但是显然有可以明显优化的空间
这里有一个可以取巧的思路:
给上一行的第一位插个0

[1, 1] => [0, 1, 1]

然后在遍历的过程中,把相邻两项相加得到当前项
代码如下:

let getRow = function(rowIndex) {
    let resultArr = [1];
    for (let i = 0; i < rowIndex; i++) {
        resultArr.unshift(0);
        for (let j = 0; j < i + 1; j++) {
            resultArr[j] = resultArr[j] + resultArr[j + 1];
        }
    }
    return resultArr;
};
值得说明的是[j + 1]由于i被插入了第一个0,所以是一定不会发生数组越界的
代码干净了不少,但是时间仍然是91.37%

3、通用优化逻辑
还有没有办法提升时间?
当然有

不管是式算还是图算,整个过程中伴随着大量的计算,仔细观察,我们可以发现杨辉三角是左右对称的。
所以可以在过半以后,把关于中轴对称的内容直接复制过来
代码如下:

let getRow = function(rowIndex) {
    let resultArr = [1];
    for (let i = 0; i < rowIndex; i++) {
        resultArr.unshift(0);
        const midIndex = Math.floor((i + 1) / 2);
        for (let j = 0; j < i + 1; j++) {
            if (j > midIndex) {
                resultArr[j] = resultArr[midIndex + ((i + 1) % 2) - (j - midIndex)];
                continue;
            }
            resultArr[j] = resultArr[j] + resultArr[j + 1];
        }
    }
    return resultArr;
};
97.2%达成ヽ( ̄▽ ̄)ノ


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值