离谱,华为食堂也要搞末位淘汰

华为饭堂 末位淘汰

今天逛职场 App,无意间翻到一篇帖子:

alt

点开图片之前,我还以为只是普通的争霸赛被网友解读为末位淘汰。

点开图片后我却发现 ...

alt

可以看出,是深圳华为的行政部做的海报,里面清晰写到:员工的每次就餐都会决定谁去谁留,结尾还用了强调不是开玩笑的感叹号。

这,实在是好家伙 🤣

先不讨论对合作供应商采取这样的规则是否合理,就连员工就餐选择都增加了莫名的压力。

对此有些网友认为,这样的规则挺好,可以迫使饭堂商家把用餐品质和服务做好,最终让就餐员工受益。

alt

但也有网友提出担心:不合理的竞争规则会加剧内卷化,最终可能会导致供应商利润被过分压缩,使得商家使用预制菜或者次品质原料来烹饪。

alt

不同类型的餐饮业因为供应链不同,利润空间相差较大。

但餐饮业也是生意,正常情况下,企业往往有个设定好的利润标准,低于标准可能就不会考虑合作。

因此现实的情况可能比网友猜想还要恶劣一些:即使尚未达到利润边界,例如可能仍有超过 20% 的利润空间,但企业通过与其他合作伙伴(非华为的客户)的利润率做横向对比,仍然会在原料上做节省操作。

...

回归主线。

今天来一道稍稍麻烦的算法题。

题目描述

平台:LeetCode

题号:2003

有一棵根节点为 0 的家族树,总共包含 n 个节点,节点编号为 0n - 1

给你一个下标从 0 开始的整数数组 parents,其中 是节点 i 的父节点。

由于节点 0 是根 ,所以

总共有 个基因值,每个基因值都用闭区间 中的一个整数表示。

给你一个下标从 0 开始的整数数组 nums,其中 是节点 i 的基因值,且基因值互不相同。

请你返回一个数组 ans,长度为 n,其中 是以节点 i 为根的子树内缺失的最小基因值。

节点 x 为根的子树包含节点 x 和它所有的后代节点。

示例 1: alt

输入:parents = [-1,0,0,2], nums = [1,2,3,4]

输出:[5,1,1,1]

解释:每个子树答案计算结果如下:
- 0:子树包含节点 [0,1,2,3] ,基因值分别为 [1,2,3,4] 。5 是缺失的最小基因值。
- 1:子树只包含节点 1 ,基因值为 2 。1 是缺失的最小基因值。
- 2:子树包含节点 [2,3] ,基因值分别为 [3,4] 。1 是缺失的最小基因值。
- 3:子树只包含节点 3 ,基因值为 4 。1是缺失的最小基因值。

示例 2: alt

输入:parents = [-1,0,1,0,3,3], nums = [5,4,6,2,1,3]

输出:[7,1,1,4,2,1]

解释:每个子树答案计算结果如下:
- 0:子树内包含节点 [0,1,2,3,4,5] ,基因值分别为 [5,4,6,2,1,3] 。7 是缺失的最小基因值。
- 1:子树内包含节点 [1,2] ,基因值分别为 [4,6] 。 1 是缺失的最小基因值。
- 2:子树内只包含节点 2 ,基因值为 6 。1 是缺失的最小基因值。
- 3:子树内包含节点 [3,4,5] ,基因值分别为 [2,1,3] 。4 是缺失的最小基因值。
- 4:子树内只包含节点 4 ,基因值为 1 。2 是缺失的最小基因值。
- 5:子树内只包含节点 5 ,基因值为 3 。1 是缺失的最小基因值。

示例 3:

输入:parents = [-1,2,3,0,2,4,1], nums = [2,3,4,5,6,7,8]

输出:[1,1,1,1,1,1,1]

解释:所有子树都缺失基因值 1 。

提示:

  • 对于 i != 0,满足
  • parents 表示一棵合法的树。
  • nums[i] 互不相同。

DFS

破题

先用几句话破题。

共由 个节点组成一棵树(节点编号从 ),parents 描述了该树的形态,同时每个节点有一个基因值

题目要我们求:以每个节点为根的子树中,权重集合在 范围内缺失的最小数

需要重点注意:是权重集合在 范围内缺失的最小数,而不是在 nums 中缺失的最小数。

举个 🌰,假设由 个节点组成树,基因值 nums = [2,3,4,5],那么对应的 ans = [1,1,1,1]

再次强调:我们求的是每个节点为根的子树中,权重集合在 范围内的最小缺失值,而非在 nums 中的缺失值。

alt
结论一:当nums 中没有 ,所有节点答案为

由于我们是求 范围内的最小缺失值,当 nums 中不存在 时,所有节点缺失的最小值为

alt
结论二:nums ,所有该节点的“非祖先”节点,答案为

基因值互不相同,同时统计的是,以每个节点为“根”时,子树的权值情况,因此节点 只会对其“祖先”产生影响。

alt
结论三:从「 节点」到「根节点」的路径中,答案必然满足“非递减”性质

这个结论不明显,但不难理解。

先假设存在某个节点 X,其最小缺失值为

alt

再通过节点 X 的最小缺失值,推理出父节点 Fa 的情况:

alt

综上,我们只需要考虑「节点 」到「根节点」这一节点答案即可。

并且由于从下往上,答案非递减,我们采取「先算子节点,再算父节点」的方式。

具体的,用变量 cur 代指当前节点,使用 ne 代指当前节点的子节点,vis 数组记录在子树中出现过的基因值,val 代表当前的节点的最小缺失值。

alt
alt
alt

一些细节:由于题目只说了 ,没说 的关系,因此我们开辟 vis 数组时需要开到 ,或是干脆使用 Set 充当 vis

Java 代码:

class Solution {
    // 考虑到有不懂「链式前向星」的同学, 这里使用最简单的存图方式 {1: [2, 3]} 代表节点一有两个子节点 2 和 3
    Map<Integer, List<Integer>> g = new HashMap<>();
    public int[] smallestMissingValueSubtree(int[] parents, int[] nums) {
        int n = nums.length, cur = -1;
        int[] ans = new int[n];
        Arrays.fill(ans, 1);
        // 找节点 1, 建图
        for (int i = 0; i < n; i++) {
            if (nums[i] == 1) cur = i;
            List<Integer> list = g.getOrDefault(parents[i], new ArrayList<>());
            list.add(i);
            g.put(parents[i], list);
        }

        // 若 nums 中没 1, 对应结论一
        if (cur == -1return ans;

        boolean[] vis = new boolean[100010];
        // 从节点 1 开始往根找(从深到浅), idx 代表当前节点, ne 代表 cur 在该链路下的子节点
        int ne = cur, val = 1;
        while (cur != -1) {
            // 每次对当前节点所在子树的进行标记
            dfs(cur, ne, nums, vis);
            // 在 [val, n+1] 范围内找第一个未被标记基因值
            for (int i = val; i <= n + 1; i++) {
                if (vis[i]) continue;
                ans[cur] = val = i;
                break;
            }
            ne = cur; cur = parents[cur]; // 指针上移
        }
        return ans;
    }
    void dfs(int idx, int block, int[] nums, boolean[] vis) {
        vis[nums[idx]] = true;
        List<Integer> list = g.getOrDefault(idx, new ArrayList<>());
        for (int x : list) {
            if (x == block) continue;
            dfs(x, block, nums, vis);
        }
    }
}

C++ 代码:

class Solution {
public:
    // 考虑到有不懂「链式前向星」的同学, 这里使用最简单的存图方式 {1: [2, 3]} 代表节点一有两个子节点 2 和 3
    unordered_map<intvector<int>> g;
    vector<intsmallestMissingValueSubtree(std::vector<int>& parents, std::vector<int>& nums) {
        int n = nums.size(), cur = -1;
        vector<intans(n, 1);
        // 找节点 1, 建图
        for (int i = 0; i < n; i++) {
            if (nums[i] == 1) cur = i;
            g[parents[i]].push_back(i);
        }
        
        // 若 nums 中没 1, 对应结论一
        if (cur == -1return ans;
        
        unordered_set<int> vis;
        // 从节点 1 开始往根找(从深到浅), idx 代表当前节点, ne 代表 cur 在该链路下的子节点
        int ne = cur, val = 1;
        while (cur != -1) {
            // 每次对当前节点所在子树的进行标记
            dfs(cur, ne, nums, vis);
            // 在 [val, n+1] 范围内找第一个未被标记基因值
            for (int i = val; i <= n + 1; i++) {
                if (vis.count(i)) continue;
                ans[cur] = val = i;
                break;
            }
            ne = cur; cur = parents[cur]; // 指针上移
        }
        return ans;
    }
    void dfs(int idx, int block, vector<int>& nums, unordered_set<int>& vis) {
        vis.insert(nums[idx]);
        for (int x : g[idx]) {
            if (x == block) continue;
            dfs(x, block, nums, vis);
        }
    }
};

Python 代码:

class Solution:
    def smallestMissingValueSubtree(self, parents: List[int], nums: List[int]) -> List[int]:
        # 虑到有不懂「链式前向星」的同学, 这里使用最简单的存图方式 {1: [2, 3]} 代表节点 1 有两个子节点 2 和 3
        g = defaultdict(list)

        def dfs(idx, block):
            nonlocal val
            vis.add(nums[idx])
            for x in g[idx]:
                if x == block:
                    continue
                dfs(x, block)
        
        n, cur = len(nums), -1
        ans = [1] * n
        # 找节点 1, 建图
        for i in range(n):
            if nums[i] == 1:
                cur = i
            g[parents[i]].append(i)
        
        # 若 nums 中没 1, 对应结论一
        if cur == -1:
            return ans
        
        vis = set()
        # 从节点 1 开始往根找(从深到浅), idx 代表当前节点, ne 代表 cur 在该链路下的子节点
        ne, val = cur, 1
        while cur != -1:
            # 每次对当前节点所在子树的进行标记
            dfs(cur, ne)
            # 在 [val, n+1] 范围内找第一个未被标记基因值
            for i in range(val, n + 2):
                if i in vis:
                    continue
                ans[cur] = val = i
                break
            ne, cur = cur, parents[cur]  # 指针上移

        return ans

TypeScript 代码:

function smallestMissingValueSubtree(parents: number[], nums: number[]): number[] {
    // 考虑到有不懂「链式前向星」的同学, 这里使用最简单的存图方式 {1: [2, 3]} 代表节点 1 有两个子节点 2 和 3
    const g = {};

    const dfs = function (g: { [key: number]: number[] }, idx: number, block: number, nums: number[], vis: Set<number>): void {
        vis.add(nums[idx]);
        if (Array.isArray(g[idx])) {
            for (let x of g[idx]) {
                if (x == block) continue;
                dfs(g, x, block, nums, vis);
            }
        }
    }

    let n = nums.length, cur = -1;
    const ans = new Array(n).fill(1);
    
    // 找节点 1, 建图
    for (let i = 0; i < n; i++) {
        if (nums[i] === 1) cur = i;
        if (![][parents[i]]) g[parents[i]] = [];
        g[parents[i]].push(i);
    }
    
    // 若 nums 中没 1, 对应结论一
    if (cur == -1return ans;
    
    const vis = new Set<number>();
    // 从节点 1 开始往根找(从深到浅), idx 代表当前节点, ne 代表 cur 在该链路下的子节点
    let ne = cur, val = 1;    
    while (cur !== -1) {
        // 每次对当前节点所在子树的进行标记
        dfs(g, cur, ne, nums, vis);
        // 在 [val, n+1] 范围内找第一个未被标记基因值
        for (let i = val; i <= n + 1; i++) {
            if (vis.has(i)) continue;
            ans[cur] = val = i;
            break;
        }
        ne = cur; cur = parents[cur];  // 指针上移
    }
    
    return ans;
}

Java 代码(链式向前星,使用 Set 充当 vis):

class Solution {
    int N = 100010, M = N, idx = 1;
    int[] he = new int[N], e = new int[M], ne = new int[M];
    void add(int a, int b) {
        e[idx] = b;
        ne[idx] = he[a];
        he[a] = idx++;
    }
    public int[] smallestMissingValueSubtree(int[] parents, int[] nums) {
        Arrays.fill(he, -1);
        int n = parents.length, cur = -1, val = 1;
        int[] ans = new int[n];
        Arrays.fill(ans, 1);
        for (int i = 0; i < n; i++) {
            if (i >= 1) add(parents[i], i);
            if (nums[i] == 1) cur = i;
        }
        if (cur == -1return ans;
        Set<Integer> vis = new HashSet();
        while (cur != -1) {
            dfs(cur, vis, nums);
            for (int i = val; i <= n + 1; i++) {
                if (vis.contains(i)) continue;
                ans[cur] = val = i;
                break;
            }
            cur = parents[cur];
        }
        return ans;
    }
    void dfs(int u, Set<Integer> vis, int[] nums) {
        vis.add(nums[u]);
        for (int i = he[u]; i != -1; i = ne[i]) {
            int j = e[i];
            if (vis.contains(nums[j])) continue;
            dfs(j, vis, nums);
        }
    }
}
  • 时间复杂度:找 和建图的复杂度为 ;构造从根节点到 节点的链条答案时,会对子树节点进行标记,同时每个节点的答案会从 范围内找缺失值,复杂度为 。 整体复杂度为
  • 空间复杂度:

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

欢迎关注,明天见。

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

本文由 mdnice 多平台发布

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

QT-地形3D

QT-地形3D 一、 演示效果二、关键程序三、下载链接 一、 演示效果 二、关键程序 #include "ShaderProgram.h"namespace t3d::core {void ShaderProgram::init() {initializeOpenGLFunctions();loadShaders(); }void ShaderProgram::addShader(const QString &fil…

如何使用Docker搭建YesPlayMusic网易云音乐播放器并发布至公网访问

文章目录 1. 安装Docker2. 本地安装部署YesPlayMusic3. 安装cpolar内网穿透4. 固定YesPlayMusic公网地址 本篇文章讲解如何使用Docker搭建YesPlayMusic网易云音乐播放器&#xff0c;并且结合cpolar内网穿透实现公网访问音乐播放器。 YesPlayMusic是一款优秀的个人音乐播放器&am…

JS逆向进阶篇【去哪儿旅行登录】【中篇-滑动轨迹破解补浏览器环境破参数】

目录&#xff1a; 每篇前言&#xff1a;0、整体分析1、逆向轨迹snapshot&#xff08;1&#xff09;分析&#xff1a;&#xff08;2&#xff09;Python轨迹生成&#xff1a;&#xff08;3&#xff09;AES加密&#xff1a;&#xff08;4&#xff09;轨迹加密&#xff1a;&#xf…

springcloud:1.Eureka详细讲解

Eureka 是 Netflix 开源的一个服务注册和发现工具,被广泛应用于微服务架构中。作为微服务架构中的核心组件之一,Eureka 提供了服务注册、发现和失效剔除等功能,帮助构建弹性、高可用的分布式系统。在现代软件开发领域,使用 Eureka 可以有效地管理和监控服务实例,实现服务之…

Qt Creator在#include第三方库不带.h后缀的文件时,没有智能提示和自动补全

1、问题截图 OSG文件目录下有很多头文件&#xff08;均不带.h后缀&#xff09;&#xff0c;Qt Creator可以识别到OSG目录&#xff0c;但是OSG目录下的所有头文件识别不到 2、原因 找到原因是因为Qt Creator开启了ClanCodeModel插件导致的 3、解决方法 1、在Qt Creator中…

GenAI的“关键一跃”:推理与知识

当前的人工智能领域正通过生成式人工智能&#xff08;GenAI&#xff09;经历一场重大转变。这一转变不仅代表了技术上的飞跃&#xff0c;更标志着人工智能领域的范式转变&#xff0c;引发了有关GenAI的独特特性及其深远影响的关键问题讨论。 植根于计算革命的丰富历史&#xff…

OpenCV人脸检测案例实战

人脸检测是一种计算机视觉技术&#xff0c;旨在识别图像或视频中的人脸。这项技术的基本内容包括使用特定的算法和模型来定位和识别人脸&#xff0c;通常涉及在图像中寻找面部特征&#xff0c;如眼睛、鼻子、嘴巴等&#xff0c;以便准确地确定人脸的位置和边界。人脸检测技术的…

LeetCode JS专栏刷题笔记(一)

一、前言 LeetCode 在前不久出了一个 JavaScript 专栏&#xff0c;这个专栏一个目的是为了非前端工程师学习 JS&#xff0c;另一个是为了前端工程师提升 JS 能力。 因此在这个专栏中&#xff0c;基本不涉及什么具体算法问题&#xff0c;都是一些 JS 的入门语法与常见的 JS 面…

安卓游戏开发之图形渲染技术优劣分析

一、引言 随着移动设备的普及和性能的提升&#xff0c;安卓游戏开发已经成为一个热门领域。在安卓游戏开发中&#xff0c;图形渲染技术是关键的一环。本文将对安卓游戏开发中常用的图形渲染技术进行分析&#xff0c;比较它们的优劣&#xff0c;并探讨它们在不同应用场景下的适用…

从零开始:开发多商户商城APP的技术指南

当下&#xff0c;电子商务正在飞速发展&#xff0c;多商户商城APP的需求也与日俱增。本篇文章&#xff0c;小编将为大家深度详解如何开发多商户商城APP。 1.确定功能需求 在着手开发多商户商城APP之前&#xff0c;首先需要明确功能需求。这包括但不限于&#xff1a; -用户注…

如何在CentOS安装SQL Server数据库并实现无公网ip环境远程连接

文章目录 前言1. 安装sql server2. 局域网测试连接3. 安装cpolar内网穿透4. 将sqlserver映射到公网5. 公网远程连接6.固定连接公网地址7.使用固定公网地址连接 前言 简单几步实现在Linux centos环境下安装部署sql server数据库&#xff0c;并结合cpolar内网穿透工具&#xff0…

MongoDB文档插入

文章目录 MongoDB文档插入对比增删改查文档插入 MongoDB写安全机制非确认式写入 MongoDB文档查询参数说明查询操作符比较查询操作符逻辑查询操作符元素查询操作符数组查询操作符 模糊查询区别:$regex操作符中的option选项 MongoDB游标介绍游标函数手动迭代游标示例游标介绍 Mon…

揭秘智能商品计划管理系统:为何服装企业老板争相引入?

在如今日新月异的商业环境中&#xff0c;服装企业老板们纷纷将目光转向了一种名为“智能商品计划管理系统”的创新工具。这种系统不仅具有高度的自动化和智能化特性&#xff0c;还能显著提升企业的运营效率、减少库存积压&#xff0c;并帮助企业在激烈的市场竞争中占据优势地位…

xilinx除法器的使用

平台&#xff1a;Vivado2018.3. 芯片&#xff1a;xcku115-flva1517-2-i (active) 最近学习使用了xilinx除法器&#xff0c;在使用过程中出现了很多次除法器的结果和我预计的结果不一致&#xff0c;特此记录学习一下。 参考文件&#xff1a;pg151.下载地址 pg151-div-gen.pdf …

简单了解一下加密算法

1.1单向散列算法 单向散列函数算法也称 Hash(哈希)算法&#xff0c;是一种将任意长度的消息压缩到某一固定长度(消 息摘要)的函数(该过程不可逆)。Hash 函数可用于数字签名、消息的完整性检测、消息起源的认 证检测等。常见的散列算法有MD5 、SHA 、RIPE-MD 、HAVAL 、N-Hash等…

【Pygame手册03/20】用 pygame 模块draw绘制形状

目录 一、说明二、画图函数2.1 接口draw下的函数2.2 pygame.draw.rect()2.3 pygame.draw.polygon()2.4 pygame.draw.circle()2.5 pygame.draw.ellipse()2.6 pygame.draw.arc()2.7 pygame.draw.line ()2.8 pygame.draw.lines()2.9 pygame.draw.aaline()2.10 pygame.draw.aaline…

【EI会议征稿通知】2024年通信安全与信息处理国际学术会议(CSIP 2024)

2024年通信安全与信息处理国际学术会议&#xff08;CSIP 2024) 2024 International Conference on Communication Security and Information Processing 随着全球信息化的深入发展&#xff0c;通信安全与信息处理已成为当今社会关注的热点问题。为了加强国际间的学术交流与合…

Java之获取Nginx代理之后的客户端IP

Java之获取Nginx代理之后的客户端IP Nginx代理接口之后&#xff0c;后台获取的IP地址都是127.0.0.1&#xff0c;解决办法是需要配置Nginx搭配后台获取的方法&#xff0c;获得设备的真实地址。我们想要获取的就是nginx代理日志中的这个IP nginx配置 首先在nginx代理的对应lo…

opencv安装介绍以及基本图像处理详解

文章目录 一、什么是OpenCV &#xff1f;二. OpenCV 安装1. 下载地址2.安装命令&#xff1a;pip install opencv-python 三、图像基础1. 基本概念2. 坐标系3. 基本操作&#xff08;彩色图片&#xff09;&#xff08;1&#xff09;读取图片&#xff1a;cv2.imread( )&#xff08…

ThreadLocal(3):ThreadLocal的内部结构

下面介绍ThreadLocal的内部结构&#xff0c;探究它能够实现线程数据隔离的原理。 1 常见的误解 ​如果我们不去看源代码的话&#xff0c;可能会猜测ThreadLocal是这样子设计的&#xff1a;每个ThreadLocal都创建一个Map&#xff0c;然后用线程作为Map的key&#xff0c;要存储…