zoukankan      html  css  js  c++  java
  • [LeetCode] 119. 杨辉三角 II

    传送门:[LeetCode] 119. 杨辉三角 II

    题目描述

    给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

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

    示例 :

    输入: 3
    输出: [1,3,3,1]

    进阶:

    • 你可以优化你的算法到 O(k) 空间复杂度吗?

    分析与代码

    • 杨辉三角的五条性质
      • 第 n 行的数字个数为 n。
      • 左右数字对称,从 1 开始到 1 结束。
      • 第 n 行的第 k 个数字为 (C_{n-1}^{k-1})
      • 第 n 行数字之和为 (2^{n-1})
      • 除了每行的第一个数字和最后一个数字,第 n 行的第 k 个数字等于第 n - 1 行的第 k - 1 个数字与第 n - 1 行 的第 k 个数字之和。
    • 注意:题目所说的行号是从 0 开始的。

    解法一:两个List

    • 使用 pre 集合保存前一行的结果,每次循环创建一个新的集合 cur 进行计算,并更新 pre 为 cur。

    代码:

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            List<Integer> pre = new ArrayList<Integer>();
            pre.add(1);
            for (int i = 1; i <= rowIndex; i++) {
                List<Integer> cur = new ArrayList<>();
                cur.add(1);
                for (int j = 1; j < i; j++) {
                    cur.add(pre.get(j - 1) + pre.get(j));
                }
                cur.add(1);
                pre = cur;
            }
            return pre;
        }
    }
    

    解法二、一个List

    • 只用一个 List,既当 pre,也当 cur。
    • 更新操作改为用 set()方法,每轮循环加上最后的 1。
    • 不能直接写row.set(j, row.get(j - 1) + row.get(j));,因为set()方法会改变当前 j 下标的值,而计算下一个 j 又需要用到之前的值,所以我们用一个变量 pre 来保存,而且每行第一个为 1,每次循环初始 pre 为 1.

    代码:

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            List<Integer> row = new ArrayList<Integer>();
            row.add(1);
            for (int i = 1; i <= rowIndex; i++) {
                int pre = 1;
                for (int j = 1; j < i; j++) {
                    int temp = row.get(j);
                    row.set(j, pre + row.get(j));
                    pre = temp;
                }
                row.add(1);
            }
            return row;
        }
    }
    

    其实也可以倒着来更新,这样就不会覆盖掉旧值。

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            List<Integer> row = new ArrayList<Integer>();
            row.add(1);
            for (int i = 1; i <= rowIndex; i++) {
                for (int j = i - 1; j >= 1; j--) {
                    row.set(j, row.get(j - 1) + row.get(j));
                }
                row.add(1);
            }
            return row;
        }
    }
    

    解法三、LinkedList队列

    • 每行循环时,先加入 1;从第二个开始,加入队列的第一个数与第二个数之和,然后移出队列第一个数,直至倒数第二个;最后加上最后一个 1,再移出第一个数。

    代码:

    class Solution {
        public List<Integer> getRow(int rowIndex) {
            LinkedList<Integer> row = new LinkedList<Integer>();
            row.add(1);
            for (int i = 1; i <= rowIndex; i++) {
                row.add(1);
                for (int j = 1; j < i; j++) {
                    row.add(row.get(0) + row.get(1));
                    row.poll();
                }
                row.add(1);
                row.poll();
            }
            return row;
        }
    }
    

    小结

    最容易想到的就是保存上一行的做法,但认真分析又发现可以只用一行也可以,更新时的覆盖旧值问题倒着来更新也不存在了,最后又看到一插一删的队列方法。



    ┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
    ┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
    ┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
    ┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
    ┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
    ┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
    ┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
    ┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
  • 相关阅读:
    /etc/sysctl.conf 控制内核相关配置文件
    python 并发编程 非阻塞IO模型
    python 并发编程 多路复用IO模型
    python 并发编程 异步IO模型
    python 并发编程 阻塞IO模型
    python 并发编程 基于gevent模块 协程池 实现并发的套接字通信
    python 并发编程 基于gevent模块实现并发的套接字通信
    python 并发编程 io模型 目录
    python 并发编程 socket 服务端 客户端 阻塞io行为
    python 并发编程 IO模型介绍
  • 原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-119.html
Copyright © 2011-2022 走看看