不要认为996是开玩笑
996 预防针
随着秋招进程的不断推进,有部分同学已经 OC,有部分同学还在苦苦挣扎,并不断降低自己的预期,包括在和 HR 沟通过程中,主动说出自己愿意接受加班,愿意接受 996,以此来博得企业方面的加分。
我的建议是,不要这么做。
不要以为 996 是开玩笑。如果在工位上的时间都已经是 996,那么投入到这份工作上的时间只会更多。
应届生一般经济情况不算宽裕,直接住在公司边上的概率较低(园区附近房子租金较高),通勤时间就算半个小时吧,这意味着 8 点左右必须起床,8 点 30 必须出发,为了避免迟到,实际情况还会比这个时间点更早;晚上下班算你 9 点准时走,到家 9 点 30,基本洗漱结束后差不多就是 11 点了。可以说一天下来,娱乐和休息两者不可兼得。
更残忍的是,这样的节奏一周有 6 天,一周休息两天和休息一天体验上千差万别。双休本质上是有完全放松的一天(周六),但单休你只能抓紧时间休息,而不敢安排其他活动,因为你还要考虑第二天 8 点起床的问题。
这就是 996 作为日常的真实分析,而非停留在口号上的感受,没试过的东西,永远不要觉得自己能轻易承受。
再强调一遍:不要以为 996 是开玩笑,不要轻易将"愿意 996"挂在嘴边。可能原本你能进入一个作息正常的部门,但因为你主动强调自己接受 996,HR 会因此另外安排你去比较卷的部门,毕竟你自己说的愿意熬。
996 作为了一个出现了几年,但还在不断被提起的长青词,你真的体验过吗?你的工作时间是什么?你对 996 的看法又是什么?一起评论区交流呀。
...
回归主题。
来一道和「校招」相关的算法原题。
题目描述
平台:LeetCode
题号:368
给你一个由无重复正整数组成的集合 nums
,请你找出并返回其中最大的整除子集 answer
,子集中每一元素对 都应当满足:answer[i] % answer[j] = 0
或 answer[j] % answer[i] = 0
。
如果存在多个有效解子集,返回其中任何一个均可。
示例 1:
输入:nums = [1,2,3]
输出:[1,2]
解释:[1,3] 也会被视为正确答案。
示例 2:
输入:nums = [1,2,4,8]
输出:[1,2,4,8]
提示:
-
nums
中的所有整数互不相同
基本分析
根据题意:「对于符合要求的「整除子集」中的任意两个值,必然满足「较大数」是「较小数」的倍数。」
数据范围是 ,我们不可能采取获取所有子集,再检查子集是否合法的爆搜解法。
通常「递归」做不了,我们就往「递推」方向去考虑。
「由于存在「整除子集」中任意两个值必然存在倍数/约数关系的性质,我们自然会想到对 nums
进行排序,然后从集合 nums
中从大到小进行取数,每次取数只考虑当前决策的数是否与「整除子集」中的最后一个数成倍数关系即可。」
这时候你可能会想枚举每个数作为「整除子集」的起点,然后从前往后遍历一遍,每次都将符合「与当前子集最后一个元素成倍数」关系的数加入答案。
举个🌰,假设有原数组 [1,2,4,8]
,“或许”我们期望的决策过程是:
-
遍历到数字 1
,此时「整除子集」为空,加到「整除子集」中; -
遍历到数字 2
,与「整除子集」的最后一个元素(1
)成倍数关系,加到「整除子集」中; -
遍历到数字 4
,与「整除子集」的最后一个元素(2
)成倍数关系,自然也与2
之前的元素成倍数关系,加到「整除子集」中; -
遍历到数字 8
,与「整除子集」的最后一个元素(4
)成倍数关系,自然也与4
之前的元素成倍数关系,加到「整除子集」中。
「但这样的做法只能够确保得到「合法解」,无法确保得到的是「最长整除子集」」。
当时担心本题数据太弱,上述错误的解法也能够通过,所以还特意实现了一下,还好被卡住了(🤣
同时也得到这个反例:[9,18,54,90,108,180,360,540,720]
,如果按照我们上述逻辑,我们得到的是 [9,18,54,108,540]
答案(长度为 5),但事实上存在更长的「整除子集」: [9,18,90,180,360,720]
(长度为 6)。
「其本质是因为同一个数的不同倍数之间不存在必然的「倍数/约数关系」,而只存在「具有公约数」的性质,这会导致我们「模拟解法」错过最优解。」
比如上述 🌰,54
& 90
和 18
存在倍数关系,但两者本身不存在倍数关系。
因此当我们决策到某一个数 nums[i]
时(nums
已排好序),我们无法直接将 nums[i]
直接接在符合「约数关系」的、最靠近位置 i
的数后面,而是要「检查位置 i
前面的所有符合「约数关系」的位置,找一个已经形成「整除子集」长度最大的数」。
「换句话说,当我们对 nums
排好序并从前往后处理时,在处理到 nums[i]
时,我们希望知道位置 i
之前的下标已经形成的「整除子集」长度是多少,然后从中选一个最长的「整除子集」,将 nums[i]
接在后面(前提是符合「倍数关系」)。」
动态规划
基于上述分析,我们不难发现这其实是一个序列 DP 问题:「某个状态的转移依赖于与前一个状态的关系。即 nums[i]
能否接在 nums[j]
后面,取决于是否满足 nums[i] % nums[j] == 0
条件。」
可看做是「最长上升子序列」问题的变形题。
「定义 为考虑前 i
个数字,且以第 i
个数为结尾的最长「整除子集」长度。」
我们不失一般性的考虑任意位置 i
,存在两种情况:
-
如果在 i
之前找不到符合条件nums[i] % nums[j] == 0
的位置j
,那么nums[i]
不能接在位置i
之前的任何数的后面,只能自己独立作为「整除子集」的第一个数,此时状态转移方程为 ; -
如果在 i
之前能够找到符合条件的位置j
,则取所有符合条件的f[j]
的最大值,代表如果希望找到以nums[i]
为结尾的最长「整除子集」,需要将nums[i]
接到符合条件的最长的nums[j]
后面,此时状态转移方程为 。
同时由于我们需要输出具体方案,需要额外使用 g[]
数组来记录每个状态是由哪个状态转移而来。
「定义 为记录 是由哪个下标的状态转移而来,如果 , 则有 。」
对于求方案数的题目,多开一个数组来记录状态从何转移而来是最常见的手段。
当我们求得所有的状态值之后,可以对 f[]
数组进行遍历,取得具体的最长「整除子集」长度和对应下标,然后使用 g[]
数组进行回溯,取得答案。
Java 代码:
class Solution {
public List<Integer> largestDivisibleSubset(int[] nums) {
Arrays.sort(nums);
int n = nums.length;
int[] f = new int[n], g = new int[n];
for (int i = 0; i < n; i++) {
// 至少包含自身一个数,因此起始长度为 1,由自身转移而来
int len = 1, prev = i;
for (int j = 0; j < i; j++) {
if (nums[i] % nums[j] == 0) {
// 如果能接在更长的序列后面,则更新「最大长度」&「从何转移而来」
if (f[j] + 1 > len) {
len = f[j] + 1;
prev = j;
}
}
}
// 记录「最终长度」&「从何转移而来」
f[i] = len; g[i] = prev;
}
// 遍历所有的 f[i],取得「最大长度」和「对应下标」
int max = -1, idx = -1;
for (int i = 0; i < n; i++) {
if (f[i] > max) {
idx = i;
max = f[i];
}
}
// 使用 g[] 数组回溯出具体方案
List<Integer> ans = new ArrayList<>();
while (ans.size() != max) {
ans.add(nums[idx]);
idx = g[idx];
}
return ans;
}
}
C++ 代码:
class Solution {
public:
vector<int> largestDivisibleSubset(vector<int>& nums) {
sort(nums.begin(), nums.end());
int n = nums.size();
vector<int> f(n, 0), g(n, 0);
for (int i = 0; i < n; i++) {
int len = 1, prev = i;
for (int j = 0; j < i; j++) {
if (nums[i] % nums[j] == 0) {
if (f[j] + 1 > len) {
len = f[j] + 1;
prev = j;
}
}
}
f[i] = len; g[i] = prev;
}
int max = -1, idx = -1;
for (int i = 0; i < n; i++) {
if (f[i] > max) {
max = f[i];
idx = i;
}
}
vector<int> ans;
while (ans.size() != max) {
ans.push_back(nums[idx]);
idx = g[idx];
}
return ans;
}
};
Python 代码:
class Solution:
def largestDivisibleSubset(self, nums: List[int]) -> List[int]:
nums.sort()
n = len(nums)
f, g = [0] * n, [0] * n
for i in range(n):
lenv, prev = 1, i
for j in range(i):
if nums[i] % nums[j] == 0:
if f[j] + 1 > lenv:
lenv, prev = f[j] + 1, j
f[i], g[i] = lenv, prev
maxv, idx = -1, -1
for i in range(n):
if f[i] > maxv:
maxv, idx = f[i], i
ans = []
while len(ans) != maxv:
ans.append(nums[idx])
idx = g[idx]
return ans
-
时间复杂度: -
空间复杂度:
证明
「之所以上述解法能够成立,问题能够转化为「最长上升子序列(LIS)」问题进行求解,本质是利用了「全序关系」中的「可传递性」。」
在 LIS 问题中,我们是利用了「关系运算符 」的传递性,因此当我们某个数 a
能够接在 b
后面,只需要确保 成立,即可确保 a
大于等于 b
之前的所有值。
那么同理,如果我们想要上述解法成立,我们还需要证明如下内容:
「倍数/约数关系」具有传递性
由于我们将 nums[i]
往某个数字后面接时(假设为 nums[j]
),只检查了其与 nums[j]
的关系,并没有去检查 nums[i]
与 nums[j]
之前的数值是否具有「倍数/约数关系」。
换句话说,我们只确保了最终答案 [a1, a2, a3, ..., an]
相邻两数值之间具有「倍数/约数关系」,并不明确任意两值之间具有「倍数/约数关系」。
因此需要证得由 和 ,可推导出 的传递性:
由 可得 由 可得
最终有 ,由于 和 都是整数,因此可得 。
得证「倍数/约数关系」具有传递性。
最后
巨划算的 LeetCode 会员优惠通道目前仍可用 ~
使用福利优惠通道 leetcode.cn/premium/?promoChannel=acoier,年度会员 有效期额外增加两个月,季度会员 有效期额外增加两周,更有超大额专属 🧧 和实物 🎁 福利每月发放。
我是宫水三叶,每天都会分享算法知识,并和大家聊聊近期的所见所闻。
欢迎关注,明天见。
更多更全更热门的「笔试/面试」相关资料可访问排版精美的 合集新基地 🎉🎉
相关文章:
不要认为996是开玩笑
996 预防针 随着秋招进程的不断推进,有部分同学已经 OC,有部分同学还在苦苦挣扎,并不断降低自己的预期,包括在和 HR 沟通过程中,主动说出自己愿意接受加班,愿意接受 996,以此来博得企业方面的加…...

精益工程师资格证书:2024年CLMP报名指南
随着全球对精益管理的需求日益增长,精益管理专业人士资格认证(CLMP)正成为越来越多精益工程师和精益管理人员提升职业竞争力的首选。作为一种注重管理而非生产的认证,CLMP不仅适用于制造业的专业人士,也吸引了各行业的…...

【Unity基础】如何选择脚本编译方式Mono和IL2CPP?
Edit -> Project Settings -> Player 在 Unity 中,Scripting Backend 决定了项目的脚本编译方式,即如何将 C# 代码转换为可执行代码。Unity 提供了两种主要的 Scripting Backend 选项:Mono 和 IL2CPP。它们之间的区别影响了项目的性能、…...
写在OceanBase开源三周年
我收获的深刻感触get 感触1:解决问题才有生存价值 [产品力] 感触2:永无止境的“易用性” [易用性] 感触3:立下“双赢”的flag 感触4:社区建设离不开用户和开发者参与 感触5:从易用到用户自助 [自助能力] 当时想法很简…...

【笔记】408刷题笔记
文章目录 三对角三叉树求最小带权路径UDP报文首部和TCP报文首部IP报文首部TCP报文首部UDP报文首部 刷新和再生的区别地址译码 为了区分队空队满,可以使用三种处理方式 1)牺牲一个单元 队头指针在队尾指针的下一位置作为队满的标志 队满条件:(…...

GitHub Star 数量前 13 的自托管项目清单
一个多月前,我们撰写并发布了这篇文章《终极自托管解决方案指南》。在那篇文章里我们深入探讨了云端服务与自托管方案的对比、自托管的潜在挑战、如何选择适合自托管解决方案,并深入介绍了五款涵盖不同场景的优秀自托管产品。 关于自托管的优势…...
js实现生成随机数值的数组
生成随机数值的数组 方法一:使用while循环和Set // min 开始数值, max 结束数值, count 数组内填充几个数值 function generateUniqueRandomNumbers(min, max, count) { let result new Set(); while (result.size < count) { let n…...

视频怎么转换成mp3格式?分享5种便捷的转换方法
在日常生活中,我们经常会遇到需要将视频文件中的音频提取出来,转换成MP3格式的情况,以便在手机、MP3播放器或其他设备上播放。今天,我将为大家介绍5种视频转MP3的方法,非常简单便捷,一起来学习下吧。 方法一…...

Reflection 70B如何革新语言模型的准确性与推理能力
在开源人工智能模型领域,HyperWrite 公司开发的 Reflection 70B 模型以其创新的“反射”机制成为新的重量级竞争者。这一模型旨在解决大型语言模型常见的“幻觉”问题,即生成不准确或虚构的信息。Reflection 70B 通过在提供最终响应之前评估和纠正自己的…...
覆盖索引是什么意思?
文章目录 Q1:覆盖索引是什么意思?覆盖索引的工作原理覆盖索引的优势覆盖索引的示例覆盖索引的使用场景覆盖索引的限制总结 Q2:为什么查询所涉及的所有字段都在索引中存在,那么数据库就无需回表?1. **索引本身存储了字段…...

最大间距问题
LeetCode164 最大间距 基数排序 #include <iostream> #include <vector> using namespace std;class Solution { public:int maximumGap(vector<int>& nums) {int nnums.size();if(n<2) return 0;int exp1;int Maxnums[0];vector<int> buf(n)…...
【Hadoop|MapReduce篇】Hadoop序列化概述
1. 什么是序列化 序列化就是把内存中的对象,转换成字节序列(或其他数据传输协议)以便于存储到磁盘(持久化)和网络传输。 反序列化就是将收到的字节序列(或其他数据传输协议)或者磁盘的持久化数…...

【Elasticsearch系列】Elasticsearch中的分页
💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

NLTK:一个强大的自然语言处理处理Python库
我是东哥,一名热爱技术的自媒体创作者。今天,我将为大家介绍一个非常有趣且强大的Python库——NLTK。无论你是刚刚接触Python的小白,还是对自然语言处理(NLP)有些许了解的朋友,NLTK都是一个值得学习的工具。…...

NUUO网络视频录像机 css_parser.php 任意文件读取漏洞复现
0x01 产品简介 NUUO网络视频录像机(Network Video Recorder,简称NVR)是NUUO Inc.生产的一种专业视频监控设备,它广泛应用于零售、交通、教育、政府和银行等多个领域。能够同时管理多个IP摄像头,实现视频录制、存储、回放及远程监控等功能。它采用先进的视频处理技术,提供…...

【支付】Stripe支付通道Java对接(产品 价格 支付 查询 退款 回调)
Stripe是一家美国科技公司,成立于2010年,由爱尔兰兄弟Patrick Collison和John Collison共同创立。该公司致力于提供高效、简洁的互联网支付收款服务,为开发者或商家提供支付API接口或代码,使商家的网站、移动APP支持信用卡付款。S…...

Unity3D 小案例 像素贪吃蛇 01 蛇的移动
Unity3D 小案例 像素贪吃蛇 第一期 蛇的移动 像素贪吃蛇 今天来简单制作一个小案例,经典的像素贪吃蛇。 准备 首先调整一下相机的设置,这里使用灰色的纯色背景,正交视图。 接着,创建一个正方形,保存为预制体&#…...

【STM32 MCU】stm32MCUs 32-bit Arm Cortex-M
stm32MCUs 32-bit Arm Cortex-M...

html+css网页设计 旅游 雪花旅行社5个页面
htmlcss网页设计 旅游 雪花旅行社5个页面 网页作品代码简单,可使用任意HTML辑软件(如:Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作)。 获取源码 1&#…...

vue3中的实例
实例类型 Vue2:每个Vue应用都是new Vue创建的一个新实例,创建的时候将data作为property添加到响应式系统中 vue3:createApp创建一个Application Instance、应用实例用来注册全局内容,大多数方法支持链式调用,返回实例…...

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式
一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明:假设每台服务器已…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...

AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...
Element Plus 表单(el-form)中关于正整数输入的校验规则
目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入(联动)2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...