25届和24届一样,涝的涝死旱的旱死

news2024/11/13 8:05:31

还是秋招

今天无意间翻到一篇帖子:

alt

帖子提到自己的求职经历:想找个产品实习岗,但连实习岗都会要求有相关工作经历...

经典的"蛋生鸡,鸡生蛋"问题。

在经历了完整的秋招后,总的感觉是"涝的涝死,旱的旱死",有些同学在纠结 BAT offers 去哪个好;有些同学 1 个 offer 别无选择;有些同学则是 0 offer 无从选择。

"涝的涝死,旱的旱死"

其实在每年秋招都会出现,只不过在 24 届和 25 届尤其明显。

原因很简单,因为这两年都是"寒冬回暖期"。

寒冬的尾巴,说明还处于"供过于求"的招聘局面,相比于盲目扩张期,虽然企业还在持续招人,但远远没有了"抢人"的那种热诚,对待应届毕业生的态度也是不温不热,有些不要脸的企业,甚至还会出现反悔违约的情况;但同时又是回暖期,意味着绝大多数企业都没有关闭招聘窗口,这给了一些能力较好的同学"集邮"(批量收割 offer)的机会。

在企业扩张期,即使不是人人都能去到自己心仪的公司,但至少绝大多数人都有实习着落,涝旱也就没有太多人关注了,在企业寒冬期,随便一砸,一片都是 0 offer 选手,10 篇帖子 9 篇负能量,涝旱言论也就浮不起来。

所以,"涝的涝死,旱的旱死"在每一届都客观存在,没必要为了这些言论影响到自己的心情,从而打乱自己的秋招计划。

随着美联储降息的拉开帷幕,CN 大概率也会跟进降息,届时企业生存难度将会有所降低,就业和消费都会有所回暖,部分热钱也会考虑回流。对于后面的应届生来说,国内公司的就业市场和外企机会都会变多,现在正是蓄力的时候,好好加油吧。

...

回归主线。

来一道和「字节跳动(校招)」相关的算法原题。

题目描述

平台:LeetCode

题号:778

在一个 N x N 的坐标方格 grid 中,每一个方格的值 表示在位置 的平台高度。

现在开始下雨了,当时间为 t 时,此时雨水导致水池中任意位置的水位为 t

你可以从一个平台游向四周相邻的任意一个平台,但是前提是此时水位必须同时淹没这两个平台。

假定你可以瞬间移动无限距离,也就是默认在方格内部游动是不耗时的。

当然,在你游泳的时候你必须待在坐标方格里面。

你从坐标方格的左上平台 出发,最少耗时多久你才能到达坐标方格的右下平台 

示例 1:

输入: [[0,2],[1,3]]

输出: 3

解释:
时间为0时,你位于坐标方格的位置为 (0, 0)。
此时你不能游向任意方向,因为四个相邻方向平台的高度都大于当前时间为 0 时的水位。
等时间到达 3 时,你才可以游向平台 (1, 1). 因为此时的水位是 3,坐标方格中的平台没有比水位 3 更高的,所以你可以游向坐标方格中的任意位置

示例2:

输入: [[0,1,2,3,4],[24,23,22,21,5],[12,13,14,15,16],[11,17,18,19,20],[10,9,8,7,6]]
输出: 16

解释:
 0  1  2  3  4
             5
12 13 14 15 16
11  
10  9  8  7  6

提示:

  • [0, ..., N*N - 1] 的排列。

Kruskal

由于在任意点可以往任意方向移动,所以相邻的点(四个方向)之间存在一条无向边。

边的权重 w 是指两点节点中的最大高度。

按照题意,我们需要找的是从左上角点到右下角点的最优路径,其中最优路径是指途径的边的最大权重值最小,然后输入最优路径中的最大权重值。

我们可以先遍历所有的点,将所有的边加入集合,存储的格式为数组 ,代表编号为 a 的点和编号为 b 的点之间的权重为 w(按照题意,w 为两者的最大高度)。

对集合进行排序,按照 w 进行从小到达排序。

当我们有了所有排好序的候选边集合之后,我们可以对边从前往后处理,每次加入一条边之后,使用并查集来查询左上角的点和右下角的点是否连通。

当我们的合并了某条边之后,判定左上角和右下角的点联通,那么该边的权重即是答案。

这道题和前天的 1631. 最小体力消耗路径 几乎是完全一样的思路。

你甚至可以将那题的代码拷贝过来,改一下对于 w 的定义即可。

Java 代码:

class Solution {
    int n;
    int[] p;
    void union(int a, int b) {
        p[find(a)] = p[find(b)];
    }
    boolean query(int a, int b) {
        return find(a) == find(b);
    }
    int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    public int swimInWater(int[][] grid) {
        n = grid.length;
        
        // 初始化并查集
        p = new int[n * n];
        for (int i = 0; i < n * n; i++) p[i] = i;

        // 预处理出所有的边
        // edge 存的是 [a, b, w]:代表从 a 到 b 所需要的时间为 w
        // 虽然我们可以往四个方向移动,但是只要对于每个点都添加「向右」和「向下」两条边的话,其实就已经覆盖了所有边了
        List<int[]> edges =  new ArrayList<>();
        for (int i = 0; i < n ;i++) {
            for (int j = 0; j < n; j++) {
                int idx = getIndex(i, j);
                p[idx] = idx;
                if (i + 1 < n) {
                    int a = idx, b = getIndex(i + 1, j);
                    int w = Math.max(grid[i][j], grid[i + 1][j]);
                    edges.add(new int[]{a, b, w});
                }
                if (j + 1 < n) {
                    int a = idx, b = getIndex(i, j + 1);
                    int w = Math.max(grid[i][j], grid[i][j + 1]);
                    edges.add(new int[]{a, b, w});
                }
            }
        }

        // 根据权值 w 升序
        Collections.sort(edges, (a,b)->a[2]-b[2]);

        // 从「小边」开始添加,当某一条边别应用之后,恰好使用得「起点」和「结点」联通
        // 那么代表找到了「最短路径」中的「权重最大的边」
        int start = getIndex(00), end = getIndex(n - 1, n - 1);
        for (int[] edge : edges) {
            int a = edge[0], b = edge[1], w = edge[2];
            union(a, b);
            if (query(start, end)) {
                return w;
            }
        }   
        return 0;
    }
    int getIndex(int i, int j) {
        return i * n + j;
    }
}

C++ 代码:

class Solution {
public:
    int n;
    vector<int> p;
    void unionSets(int x, int y) {
        p[find(x)] = find(y);
    }
    bool query(int x, int y) {
        return find(x) == find(y);
    }
    int find(int x) {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }
    int swimInWater(vector<vector<int>>& grid) {
        n = grid.size();
        p.resize(n * n);
        for (int i = 0; i < n * n; ++i) p[i] = i;

        vector<vector<int>> edges;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                int idx = i * n + j;
                if (i + 1 < n) {
                    int a = idx, b = (i + 1) * n + j;
                    int w = max(grid[i][j], grid[i + 1][j]);
                    edges.push_back({a, b, w});
                }
                if (j + 1 < n) {
                    int a = idx, b = idx + 1;
                    int w = max(grid[i][j], grid[i][j + 1]);
                    edges.push_back({a, b, w});
                }
            }
        }

        sort(edges.begin(), edges.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[2] < b[2];
        });

        int start = getIndex(00), end = getIndex(n - 1, n - 1);
        for (const auto& edge : edges) {
            unionSets(edge[0], edge[1]);
            if (query(start, end)) {
                return edge[2];
            }
        }
        return 0;
    }
    int getIndex(int i, int j) {
        return i * n + j;
    }
};

Python 代码:

class Solution:
    def __init__(self):
        self.n = 0
        self.p = []

    def union(self, x, y):
        self.p[self.find(x)] = self.find(y)

    def query(self, x, y):
        return self.find(x) == self.find(y)

    def find(self, x):
        if self.p[x] != x:
            self.p[x] = self.find(self.p[x])
        return self.p[x]

    def swimInWater(self, grid):
        self.n = len(grid)
        self.p = list(range(self.n * self.n))

        edges = []
        for i in range(self.n):
            for j in range(self.n):
                idx = i * self.n + j
                if i + 1 < self.n:
                    a, b = idx, (i + 1) * self.n + j
                    w = max(grid[i][j], grid[i + 1][j])
                    edges.append([a, b, w])
                if j + 1 < self.n:
                    a, b = idx, idx + 1
                    w = max(grid[i][j], grid[i][j + 1])
                    edges.append([a, b, w])

        edges.sort(key=lambda x: x[2])

        start, end = self.getIdx(00), self.getIdx(self.n - 1, self.n - 1)
        for edge in edges:
            self.union(edge[0], edge[1])
            if self.query(start, end):
                return edge[2]
        return 0
    
    def getIdx(self, i, j):
        return i * self.n + j

节点的数量为 ,无向边的数量严格为 ,数量级上为

  • 时间复杂度:获取所有的边复杂度为 ,排序复杂度为 ,遍历得到最终解复杂度为 。整体复杂度为
  • 空间复杂度:使用了并查集数组。复杂度为

注意:假定 JavaCollections.sort() 使用 Arrays.sort() 中的双轴快排实现。

二分 + BFS/DFS

在与本题类型的 1631. 最小体力消耗路径中,有同学问到是否可以用「二分」。

答案是可以的。

题目给定了 的范围是 ,所以答案必然落在此范围。

假设最优解为 min 的话(恰好能到达右下角的时间)。那么小于 min 的时间无法到达右下角,大于 min 的时间能到达右下角。

因此在以最优解 min 为分割点的数轴上具有两段性,可以通过「二分」来找到分割点 min

注意:「二分」的本质是两段性,并非单调性。只要一段满足某个性质,另外一段不满足某个性质,就可以用「二分」。其中 33. 搜索旋转排序数组 是一个很好的说明例子。

接着分析,假设最优解为 min,我们在 范围内进行二分,当前二分到的时间为 mid 时:

  1. 能到达右下角:必然有 ,让

  2. 不能到达右下角:必然有 ,让

当确定了「二分」逻辑之后,我们需要考虑如何写 check 函数。

显然 check 应该是一个判断给定 时间/步数 能否从「起点」到「终点」的函数。

我们只需要按照规则走特定步数,边走边检查是否到达终点即可。

实现 check 既可以使用 DFS 也可以使用 BFS。两者思路类似,这里就只以 BFS 为例。

Java 代码:

class Solution {
    int[][] dirs = new int[][]{{1,0}, {-1,0}, {0,1}, {0,-1}};
    public int swimInWater(int[][] grid) {
        int n = grid.length;
        int l = 0, r = n * n;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(grid, mid)) r = mid;    
            else l = mid + 1;
        }
        return r;
    }
    boolean check(int[][] grid, int time) {
        int n = grid.length;
        boolean[][] visited = new boolean[n][n];
        Deque<int[]> queue = new ArrayDeque<>();
        queue.addLast(new int[]{00});
        visited[0][0] = true;
        while (!queue.isEmpty()) {
            int[] pos = queue.pollFirst();
            int x = pos[0], y = pos[1];
            if (x == n - 1 && y == n - 1return true;

            for (int[] dir : dirs) {
                int newX = x + dir[0], newY = y + dir[1];
                int[] to = new int[]{newX, newY};
                if (inArea(n, newX, newY) && !visited[newX][newY] && canMove(grid, pos, to, time)) {
                    visited[newX][newY] = true;
                    queue.addLast(to);
                }
            }
        }
        return false;
    }
    boolean inArea(int n, int x, int y) {
        return x >= 0 && x < n && y >= 0 && y < n;
    }
    boolean canMove(int[][] grid, int[] from, int[] to, int time) {
        return time >= Math.max(grid[from[0]][from[1]], grid[to[0]][to[1]]);
    }
}

C++ 代码:

class Solution {
public:
    vector<vector<int>> dirs = {{10}, {-10}, {01}, {0-1}};
    int swimInWater(vector<vector<int>>& grid) {
        int n = grid.size();
        int l = 0, r = n * n;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(grid, mid)) r = mid;
            else l = mid + 1;
        }
        return r;
    }
    bool check(vector<vector<int>>& grid, int time) {
        int n = grid.size();
        vector<vector<bool>> visited(n, vector<bool>(n, false));
        queue<pair<intint>> q;
        q.push({00});
        visited[0][0] = true;
        while (!q.empty()) {
            auto pos = q.front(); q.pop();
            int x = pos.first, y = pos.second;
            if (x == n - 1 && y == n - 1return true;
            for (auto& dir : dirs) {
                int nx = x + dir[0], ny = y + dir[1];
                if (inArea(n, nx, ny) && !visited[nx][ny] && canMove(grid, {x, y}, {nx, ny}, time)) {
                    visited[nx][ny] = true;
                    q.push({nx, ny});
                }
            }
        }
        return false;
    }
    bool inArea(int n, int x, int y) {
        return x >= 0 && x < n && y >= 0 && y < n;
    }
    bool canMove(vector<vector<int>>& grid, pair<intint> from, pair<intint> to, int time) {
        return time >= max(grid[from.first][from.second], grid[to.first][to.second]);
    }
};

Python 代码:

class Solution:
    def __init__(self):
        self.dirs = [[10], [-10], [01], [0-1]]

    def swimInWater(self, grid):
        n = len(grid)
        l, r = 0, n * n
        while l < r:
            mid = l + r >> 1
            if self.check(grid, mid): r = mid
            else: l = mid + 1
        return r

    def check(self, grid, time):
        n = len(grid)
        visited = [[False] * n for _ in range(n)]
        queue = deque([(00)])
        visited[0][0] = True
        while queue:
            x, y = queue.popleft()
            if x == n - 1 and y == n - 1:
                return True
            for dx, dy in self.dirs:
                nx, ny = x + dx, y + dy
                if self.inArea(n, nx, ny) and not visited[nx][ny] and self.canMove(grid, (x, y), (nx, ny), time):
                    visited[nx][ny] = True
                    queue.append((nx, ny))
        return False
        
    def inArea(self, n, x, y):
        return 0 <= x < n and 0 <= y < n

    def canMove(self, grid, from_pos, to_pos, time):
        return time >= max(grid[from_pos[0]][from_pos[1]], grid[to_pos[0]][to_pos[1]])
  • 时间复杂度:在 范围内进行二分,复杂度为 ;每一次 BFS 最多有 个节点入队,复杂度为 。整体复杂度为
  • 空间复杂度:使用了 visited 数组。复杂度为

最后

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

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

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

欢迎关注,明天见。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2147305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于MATLAB/Simulink的模型降阶方法介绍

降阶建模ROM(Reduced order modeling) 和模型降阶MOR(Model order reduction) 是降低全阶高保真模型的计算复杂性&#xff0c;同时在令人满意的误差范围内保持预期保真度的技术。 模型降阶技术可以解决科学计算邻域在建模仿真与工程应用中的几大痛点&#xff1a; 高保真模型计…

从工厂打螺丝到数据库专家(上)

可能是年纪大了&#xff0c;近期总是失眠&#xff01;不知为何&#xff0c;这段时间心情烦躁时&#xff0c;特别喜欢听老歌&#xff0c;难道这是中年人的通病&#xff1a;都喜欢怀旧&#xff1f; 在数据库恢复订阅伙伴群&#xff0c;大家经常讨论&#xff0c;总是在回味过去&a…

文心一言 VS 讯飞星火 VS chatgpt (350)-- 算法导论24.1 1题

一、在图 24-4上运行Bellman-Ford算法&#xff0c;使用结点 z z z作为源结点。在每一遍松弛过程中&#xff0c;以图中相同的次序对每条边进行松弛&#xff0c;给出每遍松弛操作后的 d d d值和 π π π值。然后&#xff0c;把边 ( z , x ) (z,x) (z,x)的权重改为 4 4 4&#xf…

面试官:什么是CAS?存在什么问题?

大家好&#xff0c;我是大明哥&#xff0c;一个专注「死磕 Java」系列创作的硬核程序员。 回答 CAS&#xff0c;Compare And Swap&#xff0c;即比较并交换&#xff0c;它一种无锁编程技术的核心机制。其工作方式分为两步&#xff1a; 比较&#xff1a;它首先会比较内存中的某…

汉字转拼音工具类

一&#xff0c;汉字转成拼音大写首字母 public static String chineseToPinyin(String chinese) {//创建一个 StringBuilder 对象用于存储转换后的拼音。StringBuilder pinyin new StringBuilder();//创建一个汉语拼音输出格式对象。HanyuPinyinOutputFormat format new Han…

Redis-01 入门和十大数据类型

Redis支持两种持久化方式&#xff1a;RDB持久化和AOF持久化。 1.RDB持久化是将Redis的数据以快照的形式保存在磁盘上&#xff0c;可以手动触发或通过配置文件设置定时触发。RDB保存的是Redis在某个时间点上的数据快照&#xff0c;可以通过恢复RDB文件来恢复数据。 2.AOF持久化…

MySQL 中的 EXPLAIN 命令:洞察查询性能的利器

《MySQL 中的 EXPLAIN 命令&#xff1a;洞察查询性能的利器》 在 MySQL 数据库的使用中&#xff0c;优化查询性能是至关重要的一项任务。而 EXPLAIN 命令就是我们用来深入了解查询执行计划的强大工具。今天&#xff0c;我们就来一起探讨如何在 MySQL 中使用 EXPLAIN 命令&…

数据结构-3.2.栈的顺序存储实现

一.顺序栈的定义&#xff1a;top指针指向栈顶元素 1.图解&#xff1a; 2.代码&#xff1a; #include<stdio.h> #define MaxSize 10 //定义栈最多存入的元素个数 ​ typedef struct {int data[MaxSize]; //静态数组存放栈中元素int top; //栈顶指针 } SqStack; ​ int…

python mysql pymysql 数据库操作,常用脚本,个人小工具

起因&#xff0c; 目的: 整理 mysql 工具 启动数据库 检查服务器是否启动了: Get-Service -Name ‘mysql*’ 如果没启动的话&#xff0c;那么就启动: net start MySQL80 (最好是开启管理员权限) 1, 日常最常用的&#xff0c;创建连接 --> 查看所有数据库 —> 查看所有…

预处理、makefile、静动态库编写、nfs挂载、快捷命令

c查看预处理后的文件 查看执行后的汇编代码 预处理过程 静态库和动态库 静态库编写 实践 a 动态库生成 查找文件命令 动态库升级 链接的库找不到 命名要为linfun.so 执行时-lfun才能找到 系统会将lfun补充成libfun查找&#xff08;系统默认路径/user/lib/...&#xff09; 链…

C++:string 类详解

目录 简介 使用 初始化(构造函数、拷贝构造函数) 析构函数 赋值运算符重载(operator) 成员常量(npos) 运算符重载[ ](operator[ ]) size() 和 length() 迭代器( begin() 和 end() ) 范围 for 迭代器和范围 for 的比较 反向迭代器( rbegin() 和 rend() ) const 迭…

每日刷题(算法)

我们N个真是太厉害了 思路&#xff1a; 我们先给数组排序&#xff0c;如果最小的元素不为1&#xff0c;那么肯定是吹牛的&#xff0c;我们拿一个变量记录前缀和&#xff0c;如果当前元素大于它前面所有元素的和1&#xff0c;那么sum1是不能到达的值。 代码&#xff1a; #def…

elasticsearch实战应用

Elasticsearch(ES)是一种基于分布式存储的搜索和分析引擎&#xff0c;目前在许多场景得到了广泛使用&#xff0c;比如维基百科和github的检索&#xff0c;使用的就是ES。本文总结了一些使用心得体会&#xff0c;希望对大家有所帮助。 一、技术选型 说到全文搜索大家肯定会想到…

软件测试 BUG 篇

目录 一、软件测试的生命周期 二、BUG 1. bug的概念 2. 描述bug的要素 3. bug的级别 4. bug的生命周期 5. 与开发产生争执怎么办&#xff1f;&#xff08;面试高频考题&#xff09; 5.1 先检查自身&#xff0c;是否bug描述不清楚 5.2 站在用户角度考虑并抛出问题 5.3 …

[vue2+axios]下载文件+文件下载为乱码

export function downloadKnowledage(parameter) {return axios({url: /knowledage/download,method: GET,params: parameter,responseType: blob}) }添加 responseType: blob’解决以下乱码现象 使用触发a标签下载文件 downloadKnowledage(data).then((res) > {let link …

PHP及Java等其他语言转Go时选择GoFly快速快速开发框架指南

概要 经过一年多的发展GoFly快速开发框架已被一千多家科技企业或开发者用于项目开发&#xff0c;他的简单易学得到其他语言转Go首选框架。且企业版的发展为GoFly社区提供资金&#xff0c;这使得GoFly快速框架得到良好的发展&#xff0c;GoFly技术团队加大投入反哺科技企业和开…

模版进阶(template)

1.非类型模版参数 模版参数分类类型形参与非类型形参。 ① 类型形参&#xff1a;出现在在模板参数列表中&#xff0c;跟在class或者typename之类的参数类型名称。 ② 非类型形参&#xff0c;就是用一个常量作为类(函数)模板的一个参数&#xff0c;在类(函数)模板中可将该参数当…

Java键盘输入语句

编程输入语句 1.介绍:在编程中&#xff0c;需要接受用户输入的数据&#xff0c;就可以使用键盘输入语句来获取。 2.步骤&#xff1a; 1&#xff09;导入该类的所在包&#xff0c;java.util.* 2)创建该类对象&#xff08;声明变量&#xff09; 3&#xff09;调用里面的功能 3…

[2025]医院健康陪诊系统(源码+定制+服务)

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

计算机毕业设计 奖学金评定管理系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍&#xff1a;✌从事软件开发10年之余&#xff0c;专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精…