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;
        }
    }
    

    小结

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



    ┆ 然 ┆   ┆   ┆   ┆ 可 ┆   ┆   ┆ 等 ┆ 暖 ┆
    ┆ 而 ┆ 始 ┆   ┆   ┆ 是 ┆ 将 ┆   ┆ 你 ┆ 一 ┆
    ┆ 你 ┆ 终 ┆ 大 ┆   ┆ 我 ┆ 来 ┆   ┆ 如 ┆ 暖 ┆
    ┆ 没 ┆ 没 ┆ 雁 ┆   ┆ 在 ┆ 也 ┆   ┆ 试 ┆ 这 ┆
    ┆ 有 ┆ 有 ┆ 也 ┆   ┆ 这 ┆ 会 ┆   ┆ 探 ┆ 生 ┆
    ┆ 来 ┆ 来 ┆ 没 ┆   ┆ 里 ┆ 在 ┆   ┆ 般 ┆ 之 ┆
    ┆   ┆   ┆ 有 ┆   ┆   ┆ 这 ┆   ┆ 降 ┆ 凉 ┆
    ┆   ┆   ┆ 来 ┆   ┆   ┆ 里 ┆   ┆ 临 ┆ 薄 ┆
  • 相关阅读:
    今日总结
    今日总结
    今日总结
    k8s controller
    深入k8s:Informer使用及其源码分析
    理解 K8S 的设计精髓之 List-Watch机制和Informer模块
    Unix domain socket 简介
    Linux网络编程——端口复用(多个套接字绑定同一个端口)
    DPVS Tutorial
    dpvs route RTF_KNI
  • 原文地址:https://www.cnblogs.com/qiu_jiaqi/p/LeetCode-119.html
Copyright © 2011-2022 走看看