道心破碎,刚拿实习 offer 就想考公了

刚入行就想考公

进入五月,各大校招基本尘埃落定。

即使是 0 offer 选手,也表示不焦虑了,毕竟负能量也改变不了什么。

alt

而少部分拿到了 offer 的同学,也在这个校招过程中伤痕累累。

alt

一名就读于「华南农业大学」,同时「有 ACM 经历」的「计算机科班」同学发帖表示:

四月份开始找暑假实习,大厂和小厂都投了,但能拿到面试的不多,只面了「腾讯」、「美团」和「阿里」几家,最终走到最后 HR 面的是阿里。

讲道理,这是值得开心的事情,毕竟现在计算机内卷严重,0 offer 选手不在少数。

这位同学还谈到这个把月校招的一些感受:觉得现在的 IT 行业已经趋于畸形,学历只是入场券,需要有好的简历和比赛经历才能到下一步,八股文和底层都需要有所了解,算法的考察也偏向于竞赛,以及面试过程中和面试官的同频与否也是决定性因素。

之后还谈到了虽然拿到了 offer,但不想再卷技术了,只想平静的活着,目前在往考公的方向进行考虑。

怎么说呢。

其实不限于计算机的同学,任何应届毕业生都会有这种情绪。

首先,我们要区分清楚「自己是对于离开校园,投身社会,对未来不确定性的恐惧」还是「真心不喜欢自己将要投身的行业,感到厌倦」

想要得到前者的肯定回答,是很难的,因为往往当局者迷;但想要得到后者的否定回答,是很容易的,任何一个在脑袋中一闪而过的理由即可。

因此,如果不是「不喜欢自己将要投身的行业」的话,问题就变得简单了。

克服对未来的恐惧的最好方法,就是专注于身边的事情,例如,为马上到来的实习经历做准备。

专注于完成学校里剩下的任务、专注于找实习期间住的地方、甚至专注于和将要道别的同学室友聚会 ...

想做什么都可以。

把自己交给生活,生活有质量,时间有速度,只要专注起来,很快那种不踏实的感觉就会消失。

那,如果是「真心不喜欢自己将要投身的行业」的情况呢?

这时候需要从理性的角度进行分析。

我想起来我一位朋友,甚至也曾是 oier,后来也因为对编程腻了,转行了。

考虑到今天唠嗑篇幅差不多了,留到下回分解吧,给大家留点脑力做题。

...

回归主线。

既然帖子中的同学提到现在笔试面试有变难的趋势,那就来一道稍有难度的题目。

题目描述

平台:LeetCode

题号:1697

给你一个 n 个点组成的无向图边集 edgeList,其中   表示点  和点   之间有一条长度为   的边。请注意,两个点之间可能有 超过一条边 。

给你一个查询数组 queries,其中   ,你的任务是对于每个查询   ,判断是否存在从   到   的路径,且这条路径上的每一条边都 严格小于   。

请你返回一个 布尔数组 answer,其中 answer.length == queries.length,当   的查询结果为 true 时, answer 第 j 个值为 true ,否则为 false 。

示例 1: alt

输入:n = 3, edgeList = [[0,1,2],[1,2,4],[2,0,8],[1,0,16]], queries = [[0,1,2],[0,2,5]]

输出:[false,true]

解释:上图为给定的输入数据。注意到 0 和 1 之间有两条重边,分别为 2 和 16 。
对于第一个查询,0 和 1 之间没有小于 2 的边,所以我们返回 false 。
对于第二个查询,有一条路径(0 -> 1 -> 2)两条边都小于 5 ,所以这个查询我们返回 true 。

示例 2: alt

输入:n = 5, edgeList = [[0,1,10],[1,2,5],[2,3,9],[3,4,13]], queries = [[0,4,14],[1,4,13]]

输出:[true,false]

解释:上图为给定数据。

提示:

  • 两个点之间可能有多条边。

排序 + 并查集 + 双指针

为了方便,我们将点数记为 n,边数记为 m,询问数量记为 k,将 edgeList 简化为 es,将 queries 简化为 qs

对于点边数量都在 ,同时询问次数也在 的问题,不可能对于每个询问执行最短路算法,尤其还需考虑边权限制。

「对于一个询问 而言,等价于问我们使用所有边权小于 limit 的边,能否使得 ab 两点联通。」

关于回答连通性问题,容易想到并查集。同时我们可以通过「调整回答询问的顺序」来降低复杂度(避免重复重置并查集和添加某些边),即转换为离线问题来处理。

何为离线问题?预先知道所有询问,能够通过调整回答询问的顺序,来降低算法复杂度。同时不同询问相互独立,不会因为调整询问顺序,对每个询问的结果造成影响。例如莫队算法。

具体的,我们可以对边集 es 和所有询问 qs 分别按照「边权」以及「限制」排升序。为了排序后,仍能知道当前询问的原编号,我们要将所有的 qs[i] 转换为四元组。

随后从前往后处理每个询问 qs[i] = (a, b, t, idx),同时使用变量 j 来记录当前处理到的边。在查询 ab 是否连通前,先将边集 es 中所有所有边权小于 t 的边应用到并查集上,从而实现每次 ans[idx] = query(a, b) 查询到的是原图中所有边权小于限制值 t 的子图。

Java 代码:

class Solution {
    static int N = 100010;
    static int[] p = new int[N];
    int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    void union(int a, int b) {
        p[find(a)] = p[find(b)];
    }
    boolean query(int a, int b) {
        return find(a) == find(b);
    }
    public boolean[] distanceLimitedPathsExist(int n, int[][] es, int[][] _qs) {
        for (int i = 0; i < n; i++) p[i] = i;
        int m = es.length, k = _qs.length;
        int[][] qs = new int[k][4];
        for (int i = 0; i < k; i++) qs[i] = new int[]{_qs[i][0], _qs[i][1], _qs[i][2], i};
        Arrays.sort(qs, (a,b)->a[2]-b[2]);
        Arrays.sort(es, (a,b)->a[2]-b[2]);
        boolean[] ans = new boolean[k];
        for (int i = 0, j = 0; i < k; i++) {
            int a = qs[i][0], b = qs[i][1], t = qs[i][2], idx = qs[i][3];
            while (j < m && es[j][2] < t) {
                union(es[j][0], es[j][1]);
                j++;
            }
            ans[idx] = query(a, b);
        }
        return ans;
    }
}

C++ 代码:

class Solution {
public:
    int p[100010];
    int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    void unite(int a, int b) {
        p[find(a)] = find(b);
    }
    bool query(int a, int b) {
        return find(a) == find(b);
    }
    vector<booldistanceLimitedPathsExist(int n, vector<vector<int>>& es, vector<vector<int>>& qs) {
        for (int i = 0; i < n; i++) p[i] = i;
        int m = es.size(), k = qs.size();
        vector<vector<int>> qss(k, vector<int>(40));
        for (int i = 0; i < k; i++) qss[i] = {qs[i][0], qs[i][1], qs[i][2], i};
        sort(qss.begin(), qss.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[2] < b[2];
        });
        sort(es.begin(), es.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[2] < b[2];
        });
        vector<boolans(k, false);
        for (int i = 0, j = 0; i < k; i++) {
            int a = qss[i][0], b = qss[i][1], t = qss[i][2], idx = qss[i][3];
            while (j < m && es[j][2] < t) {
                unite(es[j][0], es[j][1]);
                j++;
            }
            ans[idx] = query(a, b);
        }
        return ans;
    }
};

Python 代码:

class Solution:
    def distanceLimitedPathsExist(self, n: int, es: List[List[int]], _qs: List[List[int]]) -> List[bool]:
        p = [i for i in range(n)]
        def find(x):
            if p[x] != x:
                p[x] = find(p[x])
            return p[x]
        def union(a, b):
            p[find(a)] = p[find(b)]
        def query(a, b):
            return find(a) == find(b)
        m, k = len(es), len(_qs)
        qs = [(a, b, c, i) for i, (a, b, c) in enumerate(_qs)]
        es.sort(key=lambda x: x[2])
        qs.sort(key=lambda x: x[2])
        j = 0
        ans = [False] * k
        for i in range(k):
            a, b, t, idx = qs[i]
            while j < m and es[j][2] < t:
                union(es[j][0], es[j][1])
                j += 1
            ans[idx] = query(a, b)
        return ans

TypeScript 代码:

function distanceLimitedPathsExist(n: number, es: number[][], _qs: number[][]): boolean[] {
    const p = new Array<number>(n).fill(0)
    for (let i = 0; i < n; i++) p[i] = i;
    function find(x: number): number {
        if (p[x] != x) p[x] = find(p[x])
        return p[x]
    }
    function union(a: number, b: number): void {
        p[find(a)] = p[find(b)]
    }
    function query(a: number, b: number): boolean {
        return find(a) == find(b)
    }
    const m = es.length, k = _qs.length
    const qs = []
    for (let i = 0; i < k; i++) qs.push([_qs[i][0], _qs[i][1], _qs[i][2], i])
    qs.sort((a, b)=>a[2]-b[2])
    es.sort((a, b)=>a[2]-b[2])
    const ans = new Array<boolean>(k).fill(false)
    for (let i = 0, j = 0; i < k; i++) {
        const a = qs[i][0], b = qs[i][1], t = qs[i][2], idx = qs[i][3]
        while (j < m && es[j][2] < t) {
            union(es[j][0], es[j][1])
            j++
        }
        ans[idx] = query(a, b)
    }
    return ans
}
  • 时间复杂度:初始化并查集的复杂度为 ;对所有边进行排序复杂度为 ;对所有询问进行排序复杂度为 ;统计答案时使用双指针的方式将所有边运用到并查集上,整体复杂度为 。整体复杂度为
  • 空间复杂度:

最后

给大伙通知一下 📢 :

全网最低价 LeetCode 会员目前仍可用 ~

📅 年度会员:有效期加赠两个月!!; 季度会员:有效期加赠两周!!

🧧 年度会员:获 66.66 现金红包!!; 季度会员:获 22.22 现金红包!!

🎁 年度会员:参与当月丰厚专属实物抽奖(中奖率 > 30%)!!

专属链接:leetcode.cn/premium/?promoChannel=acoier

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

欢迎关注,明天见。

更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值