偷偷签了比亚迪,不敢告诉实验室和导师

教育   2024-12-03 14:26   上海  

比亚迪

随着华为(几乎是最晚一家)开奖,秋招基本也进入最后的尾声。

与网上那些动辄 20k+ 的 SP/SSP 玩家不同,今天看到一篇格外真实的帖子:

发帖的同学说到,随着秋招的结束,自己偷偷签下了比亚迪,虽然做的项目很有趣,但相比于自己的专业,仍然感觉自己是转行了。入职比亚迪的事儿,至今不敢告诉实验室的小伙伴和导师。除了专业不对口,还担心入职比亚迪会不被认可。

确实,比亚迪和其他互联网大厂不同,很少会根据面试者具体表现来划分「白菜/SP/SSP」几个档位,更多就是简单的按照「学历」来给 Offer。

这一模式也引发了很多同学的不满,感觉自己大学几年的努力都被无视了,导致比亚迪在应届生的侯选 List 中一直比较靠后,几乎就是鄙视链的底端。

但怎么说呢?适合自己的才是最好的。

每年应届生这么多,哪能个个都拿头牌大厂的 SP?

尤其对于应届生来说,首份工作对于"成长性"的考量应当是要高于"薪资待遇"方面的,而且「应届校招」也是「选择加入自己喜欢的行业(转行)」的最好时机。

要知道,如果毕业几年后,再想加入某个行业,可没有校招路线可走。社招对行业经验的要求几乎是不可避免的,即使通过"特训"手段,通过了面试,混入了某个公司,也不会有人把你当成白纸来培养,因此在工作中得到系统成长的机会几乎为零。

...

回归主题。

来一道玩法繁多的算法题,看你能撑到第几关。

题目描述

平台:LeetCode

题号:1137

泰波那契序列 定义如下:

, , , 且在 的条件下

给你整数 ,请返回第 个泰波那契数 的值。

示例 1:

输入:n = 4

输出:4

解释:
T_3 = 0 + 1 + 1 = 2
T_4 = 1 + 1 + 2 = 4

示例 2:

输入:n = 25

输出:1389537

提示:

  • 答案保证是一个 位整数,即

动态规划(迭代)

都直接给出状态转移方程了,其实就是道模拟题。

使用三个变量,从前往后算一遍即可。

Java 代码:

class Solution {
    public int tribonacci(int n) {
        if (n == 0return 0;
        if (n == 1 || n == 2return 1;
        int a = 0, b = 1, c = 1;
        for (int i = 3; i <= n; i++) {
            int d = a + b + c;
            a = b; b = c; c = d;
        }
        return c;
    }
}

C++ 代码:

class Solution {
public:
    int tribonacci(int n) {
        if (n == 0return 0;
        if (n == 1 || n == 2return 1;
        int a = 0, b = 1, c = 1;
        for (int i = 3; i <= n; i++) {
            int d = a + b + c;
            a = b; b = c; c = d;
        }
        return c;
    }
};

Python 代码:

class Solution:
    def tribonacci(self, n: int) -> int:
        if n == 0return 0
        if n == 1 or n == 2return 1
        a, b, c = 011
        for i in range(3, n + 1):
            d = a + b + c
            a, b, c = b, c, d
        return c

TypeScript 代码:

function tribonacci(n: number): number {
    if (n === 0return 0;
    if (n === 1 || n === 2return 1;
    let a = 0, b = 1, c = 1;
    for (let i = 3; i <= n; i++) {
        const d = a + b + c;
        a = b; b = c; c = d;
    }
    return c;
};
  • 时间复杂度:
  • 空间复杂度:

动态规划(递归)

也就是记忆化搜索,创建一个 cache 数组用于防止重复计算。

Java 代码:

class Solution {
    int[] cache = new int[40];
    public int tribonacci(int n) {
        if (n == 0return 0;
        if (n == 1 || n == 2return 1;
        if (cache[n] != 0return cache[n];
        cache[n] = tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3); 
        return cache[n];
    }
}

C++ 代码:

class Solution {
public:
    vector<int> cache = vector<int>(400);
    int tribonacci(int n) {
        if (n == 0return 0;
        if (n == 1 || n == 2return 1;
        if (cache[n] != 0return cache[n];
        cache[n] = tribonacci(n - 1) + tribonacci(n - 2) + tribonacci(n - 3); 
        return cache[n];
    }
};

Python 代码:

class Solution:
    def __init__(self):
        self.cache = [0] * 40
    def tribonacci(self, n: int) -> int:
        if n == 0return 0
        if n == 1 or n == 2return 1
        if self.cache[n] != 0return self.cache[n]
        self.cache[n] = self.tribonacci(n - 1) + self.tribonacci(n - 2) + self.tribonacci(n - 3)
        return self.cache[n]
  • 时间复杂度:
  • 空间复杂度:

矩阵快速幂

这还是一道「矩阵快速幂」的板子题。

首先你要对「快速幂」和「矩阵乘法」概念有所了解。

矩阵快速幂用于求解一般性问题:给定大小为 的矩阵 ,求答案矩阵 ,并对答案矩阵中的每位元素对 取模。

在上述两种解法中,当我们要求解 时,需要将 都算一遍,因此需要线性的复杂度。

对于此类的「数列递推」问题,我们可以使用「矩阵快速幂」来进行加速(比如要递归一个长度为 的数列,线性复杂度会被卡)。

使用矩阵快速幂,我们只需要 的复杂度。

根据题目的递推关系():

我们发现要求解 ,其依赖的是

我们可以将其存成一个列向量:

当我们整理出依赖的列向量之后,不难发现,我们想求的 所在的列向量是这样的:

利用题目给定的依赖关系,对目标矩阵元素进行展开:

那么根据矩阵乘法,即有:

我们令

然后发现,利用 我们也能实现数列递推(公式太难敲了,随便列两项吧):

再根据矩阵运算的结合律,最终有:

从而将问题转化为求解 ,这时候可以套用「矩阵快速幂」解决方案。

Java 代码:

class Solution {
    int N = 3;
    int[][] mul(int[][] a, int[][] b) {
        int[][] c = new int[N][N];
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];
            }
        }
        return c;
    }
    public int tribonacci(int n) {
        if (n == 0return 0;
        if (n == 1 || n == 2return 1;
        int[][] ans = new int[][]{
            {1,0,0},
            {0,1,0},
            {0,0,1}
        };
        int[][] mat = new int[][]{
            {1,1,1},
            {1,0,0},
            {0,1,0}
        };
        int k = n - 2;
        while (k != 0) {
            if ((k & 1) != 0) ans = mul(ans, mat);
            mat = mul(mat, mat);
            k >>= 1;
        }
        return ans[0][0] + ans[0][1];
    }
}

C++ 代码:

class Solution {
public:
    int N = 3;
    vector<vector<long long>> mul(vector<vector<long long>>& a, vector<vector<long long>>& b) {
        vector<vector<long long>> c(N, vector<long long>(N, 0));
        for (int i = 0; i < N; i++) {
            for (int j = 0; j < N; j++) {
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];
            }
        }
        return c;
    }
    int tribonacci(int n) {
        if (n == 0return 0;
        if (n == 1 || n == 2return 1;
        vector<vector<long long>> ans = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
        vector<vector<long long>> mat = {{1, 1, 1}, {1, 0, 0}, {0, 1, 0}};
        int k = n - 2;
        while (k != 0) {
            if ((k & 1) != 0) ans = mul(ans, mat);
            mat = mul(mat, mat);
            k >>= 1;
        }
        return ans[0][0] + ans[0][1];
    }
};

Python 代码:

class Solution:
    def __init__(self):
        self.N = 3

    def mul(self, a, b):
        c = [[0] * self.N for _ in range(self.N)]
        for i in range(self.N):
            for j in range(self.N):
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j]
        return c

    def tribonacci(self, n: int) -> int:
        if n == 0return 0
        if n == 1 or n == 2return 1
        ans = [[100], [010], [001]]
        mat = [[111], [100], [010]]
        k = n - 2
        while k != 0:
            if k & 1: ans = self.mul(ans, mat)
            mat = self.mul(mat, mat)
            k >>= 1
        return ans[0][0] + ans[0][1]

TypeScript 代码:

function tribonacci(n: number): number {
    const N = 3;
    const mul = function(a: number[][], b: number[][]): number[][] {
        const c = Array.from({ length: N }, () => Array(N).fill(0));
        for (let i = 0; i < N; i++) {
            for (let j = 0; j < N; j++) {
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];
            }
        }
        return c;
    };
    if (n === 0return 0;
    if (n === 1 || n === 2return 1;
    let ans = [[100], [010], [001]];
    let mat = [[111], [100], [010]];
    let k = n - 2;
    while (k !== 0) {
        if (k & 1) ans = mul(ans, mat);
        mat = mul(mat, mat);
        k >>= 1;
    }
    return ans[0][0] + ans[0][1];
};
  • 时间复杂度:
  • 空间复杂度:

打表

当然,我们也可以将数据范围内的所有答案进行打表预处理,然后在询问时直接查表返回。

但对这种题目进行打表带来的收益没有平常打表题的大,因为打表内容不是作为算法必须的一个环节,而直接是作为该询问的答案,但测试样例是不会相同的,即不会有两个测试数据都是

这时候打表节省的计算量是不同测试数据之间的相同前缀计算量,例如 ,其 之前的计算量只会被计算一次。

因此直接为「解法二」的 cache 添加 static 修饰其实是更好的方式:代码更短,同时也能起到同样的节省运算量的效果。

Java 代码:

class Solution {
    static int[] cache = new int[40];
    static {
        cache[0] = 0; cache[1] = 1; cache[2] = 1;
        for (int i = 3; i < cache.length; i++) {
            cache[i] = cache[i - 1] + cache[i - 2] + cache[i - 3];
        }
    }
    public int tribonacci(int n) {
        return cache[n];
    }
}

C++ 代码:

class Solution {
public:
    static vector<long long> cache;
    Solution() {
        cache.resize(40);
        cache[0] = 0; cache[1] = 1; cache[2] = 1;
        for (int i = 3; i < 40; ++i) {
            cache[i] = cache[i - 1] + cache[i - 2] + cache[i - 3];
        }
    }
    int tribonacci(int n) {
        return static_cast<int>(cache[n]);
    }
};
vector<long long> Solution::cache;

Python 代码:

class Solution:
    cache = [011] + [0] * 37
    for i in range(340):
        cache[i] = cache[i - 1] + cache[i - 2] + cache[i - 3]

    def tribonacci(self, n: int) -> int:
        return self.cache[n]
  • 时间复杂度:将打表逻辑交给 ,复杂度为 固定为 。将打表逻辑放到本地进行,复杂度为
  • 空间复杂度:

最后

巨划算的 LeetCode 会员优惠通道目前仍可用 ~

使用福利优惠通道 leetcode.cn/premium/?promoChannel=acoier,年度会员 有效期额外增加两个月,季度会员 有效期额外增加两周,更有超大额专属 🧧 和实物 🎁 福利每月发放。

我是宫水三叶,每天都会分享算法知识,并和大家聊聊近期的所见所闻

欢迎关注,明天见。



宫水三叶的刷题日记
锐评时事热点的 算法与数据结构 题解区博主。「 刷穿 LeetCode 」系列文章原创公众号。
 最新文章