年终奖,还得是腾讯(含面试算法原题)

腾讯年终奖

什么是真正的好公司?

一年到头,出不了几次裁员等劳务纠纷的吃瓜新闻。

只有到年底了,才因为年终奖远高于行业水平,实在没法低调了,"被迫"上热搜。

最近网友爆料了腾讯头牌部门的年终奖:

WXG(微信事业群):

  • 第一档:30 个月(视频号 - 优秀)
  • 第二档:20 个月(视频号 - 一般)
  • 第三档:16 个月(WXG - 一般)
  • 其它:不足 10 个月(WXG - 垫底水平)

IEG(互动娱乐事业群:天美工作室 and 光子工作室 and 其他):

  • 第一档:25 个月(元梦之星、王者荣耀 - 优秀)
  • 第二档:15 个月(元梦之星、王者荣耀 - 一般)
  • 第三档:9 个月(天美工作室 - 优秀)
  • 第四档:5 个月(光子工作室 - 一般)
  • 其它:3 - 4 个月(IEG - 垫底水平)

上述数据都是来自网友爆料,真实性不能保证。

但即使是真的,其实也不能真实反映腾讯整体年终奖水平。

毕竟 WXG 和 IEG 可是腾讯绝对的头牌事业群,年终奖肯定是要远高于中位数的。

当然,头不头牌的其实也不影响大家 🍋🍋:

15 个月的八折,12 个月,就是没有年终奖。

这年头上个网,没有年终奖可以,但没有幽默感可不行。

真正让我感到震惊的,是这条网友评论:

腾讯年终奖,我已经分不清他们到底是不是在凡尔赛了。

一位腾讯在职的网友留言:"年终奖只有 4.5 个月,要润么?"

这是真诚发问呢,还是在凡尔赛?

我怎么感觉,这位网友越是真诚发问,就越凡尔赛呢 😂

...

回归主线。

来一道稍有难度的「腾讯」面试算法题。

主要目的,是把大家「没去腾讯,太可惜了」的小思绪往下摁一摁。

题目描述

平台:LeetCode

题号:2305

给你一个整数数组 cs,其中 cs[i] 表示在第 i 个零食包中的饼干数量。

另给你一个整数 k 表示等待分发零食包的孩子数量,所有零食包都需要分发。

在同一个零食包中的所有饼干都必须分发给同一个孩子,不能分开。

分发的不公平程度定义为单个孩子在分发过程中能够获得饼干的最大总数。

返回所有分发的最小不公平程度。

示例 1:

ini 复制代码
输入:cs = [8,15,10,20,8], k = 2

输出:31

解释:一种最优方案是 [8,15,8] 和 [10,20] 。
- 第 1 个孩子分到 [8,15,8] ,总计 8 + 15 + 8 = 31 块饼干。
- 第 2 个孩子分到 [10,20] ,总计 10 + 20 = 30 块饼干。
分发的不公平程度为 max(31,30) = 31 。
可以证明不存在不公平程度小于 31 的分发方案。

示例 2:

ini 复制代码
输入:cs = [6,1,3,2,2,4,1,2], k = 3

输出:7

解释:一种最优方案是 [6,1]、[3,2,2] 和 [4,1,2] 。
- 第 1 个孩子分到 [6,1] ,总计 6 + 1 = 7 块饼干。 
- 第 2 个孩子分到 [3,2,2] ,总计 3 + 2 + 2 = 7 块饼干。
- 第 3 个孩子分到 [4,1,2] ,总计 4 + 1 + 2 = 7 块饼干。
分发的不公平程度为 max(7,7,7) = 7 。
可以证明不存在不公平程度小于 7 的分发方案。

提示:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 < = c s . l e n g t h < = 8 2 <= cs.length <= 8 </math>2<=cs.length<=8
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = c s [ i ] < = 1 0 5 1 <= cs[i] <= 10^5 </math>1<=cs[i]<=105
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 < = k < = c s . l e n g t h 2 <= k <= cs.length </math>2<=k<=cs.length

状压 DP

定义 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ i ] [ s ] f[i][s] </math>f[i][s] 为考虑前 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 个人,对 cs 的分配情况为 s 时的最小不公平程度。

其中 s 为一个二进制数,若 s 的第 i 位为 1 代表 cs[i] 已被分配,反之代表未分配。同时我们可以预处理 g 数组,g[s] = t 含义为选择 cs 状态为 s 时得到的饼干总和为 t

初始化只有 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ 0 ] [ 0 ] = 0 f[0][0] = 0 </math>f[0][0]=0,其余均为正无穷 0x3f3f3f3f

不失一般性考虑 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ i ] [ s ] f[i][s] </math>f[i][s] 该如何计算,通过枚举第 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 个小朋友所分配到的饼干情况 ps 的子集)进行转移 :若第 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 个小朋友分配到的饼干情况为 p,则此前 <math xmlns="http://www.w3.org/1998/Math/MathML"> i − 1 i - 1 </math>i−1 个小朋友分配到饼干情况为 <math xmlns="http://www.w3.org/1998/Math/MathML"> s − p s - p </math>s−p,前 <math xmlns="http://www.w3.org/1998/Math/MathML"> i − 1 i - 1 </math>i−1 个小朋友的最小不公平程度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ i − 1 ] [ s − p ] f[i - 1][s - p] </math>f[i−1][s−p],当前第 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 个小朋友的不公平程度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> g [ p ] g[p] </math>g[p],两者中最大值可用于更新 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ i ] [ s ] f[i][s] </math>f[i][s]。
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> f [ i ] [ s ] = min ⁡ ( f [ i ] [ s ] , max ⁡ ( f [ i − 1 ] [ s − p ] , g [ p ] ) ) , p ⊆ s f[i][s] = \min(f[i][s], \max(f[i - 1][s - p], g[p])), p \subseteq s </math>f[i][s]=min(f[i][s],max(f[i−1][s−p],g[p])),p⊆s

最终 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ k ] [ 2 n − 1 ] f[k][2^n - 1] </math>f[k][2n−1] 即是答案。

Java 代码:

Java 复制代码
class Solution {
    public int distributeCookies(int[] cs, int k) {
        int n = cs.length, mask = 1 << n, INF = 0x3f3f3f3f;
        int[] g = new int[mask];
        for (int s = 0; s < mask; s++) {
            int t = 0;
            for (int i = 0; i < n; i++) t += ((s >> i) & 1) == 1 ? cs[i] : 0;
            g[s] = t;
        }
        int[][] f = new int[k + 10][mask];
        for (int i = 0; i <= k; i++) Arrays.fill(f[i], INF);
        f[0][0] = 0;
        for (int i = 1; i <= k; i++) {
            for (int s = 0; s < mask; s++) {
                for (int p = s; p != 0; p = (p - 1) & s) {
                    f[i][s] = Math.min(f[i][s], Math.max(f[i - 1][s - p], g[p]));
                }
            }
        }
        return f[k][mask - 1];
    }
}

Python 代码:

Python 复制代码
class Solution:
    def distributeCookies(self, cs: List[int], k: int) -> int:
        n, mask, INF = len(cs), 1 << len(cs), 0x3f3f3f3f
        g = [0] * mask
        for s in range(mask):
            t = 0
            for i in range(n):
                t += cs[i] if (s >> i) & 1 == 1 else 0
            g[s] = t
        f = [[INF] * mask for _ in range(k + 10)]
        f[0][0] = 0
        for i in range(1, k + 1):
            for s in range(mask):
                p = s
                while p != 0:
                    f[i][s] = min(f[i][s], max(f[i - 1][s - p], g[p]))
                    p = (p - 1) & s
        return f[k][mask - 1]

C++ 代码:

C++ 复制代码
class Solution {
public:
    int distributeCookies(vector<int>& cs, int k) {
        int n = cs.size(), mask = 1 << n, INF = 0x3f3f3f3f;
        vector<int> g(mask, 0);
        for (int s = 0; s < mask; s++) {
            int t = 0;
            for (int i = 0; i < n; i++) t += ((s >> i) & 1) == 1 ? cs[i] : 0;
            g[s] = t;
        }
        vector<vector<int>> f(k + 10, vector<int>(mask, INF));
        for (int i = 0; i <= k; i++) fill(f[i].begin(), f[i].end(), INF);
        f[0][0] = 0;
        for (int i = 1; i <= k; i++) {
            for (int s = 0; s < mask; s++) {
                for (int p = s; p != 0; p = (p - 1) & s) {
                    f[i][s] = min(f[i][s], max(f[i - 1][s - p], g[p]));
                }
            }
        }
        return f[k][mask - 1];
    }
};

TypeScirpt 代码:

TypeScript 复制代码
function distributeCookies(cs: number[], k: number): number {
    const n = cs.length, mask = 1 << n, INF = 0x3f3f3f3f;
    const g = new Array(mask).fill(0);
    for (let s = 0; s < mask; s++) {
        let t = 0;
        for (let i = 0; i < n; i++) t += ((s >> i) & 1) === 1 ? cs[i] : 0;
        g[s] = t;
    }
    const f = new Array(k + 10).fill(0).map(() => new Array(mask).fill(INF));
    f[0][0] = 0;
    for (let i = 1; i <= k; i++) {
        for (let s = 0; s < mask; s++) {
            for (let p = s; p != 0; p = (p - 1) & s) {
                f[i][s] = Math.min(f[i][s], Math.max(f[i - 1][s - p], g[p]));
            }
        }
    }
    return f[k][mask - 1];
};
  • 时间复杂度:将 cs 长度记为 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n,状态数量记为 <math xmlns="http://www.w3.org/1998/Math/MathML"> m = 2 n m = 2^n </math>m=2n,预处理复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n × m ) O(n \times m) </math>O(n×m);DP 过程需要枚举二进制长度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 的所有子集的子集,复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( 3 n ) O(3^n) </math>O(3n),DP 过程复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( k × 3 n ) O(k \times 3^n) </math>O(k×3n)。整体复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( k × 3 n ) O(k \times 3^n) </math>O(k×3n)
  • 空间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( k × m ) O(k \times m) </math>O(k×m)

小答疑

其实关于为什么要用 0x3f3f3f3f 来充当 ♾️,每次都会在评论区进行答疑。

这次干脆整合到文章中好了。

为什么使用 0x3f3f3f3f 来充当 ♾️,而不是使用其他诸如 INT_MAX 来充当 ♾️?

首先, 0x3f3f3f3fINT_MAX 均为同一数量级,均大于一般的数据范围 10^9,均能满足 ♾️ 要求,这是前提。

另外,使用 0x3f3f3f3f 相比于使用 INT_MAX ,有如下的额外好处:

  1. 0x3f3f3f3f 乘 <math xmlns="http://www.w3.org/1998/Math/MathML"> 2 2 </math>2 不会发生溢出
  2. 0x3f3f3f3f 每字节都是 0x3f,因此 C++ 可以直接通过 memset(array, 0x3f, sizeof(array)) 的方式来得到一个初始值为无穷大的数组,而无需使用循环赋值的方式来做

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

欢迎关注,明天见。

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

相关推荐
夜流冰21 分钟前
工具方法 - 面试中回答问题的技巧
面试·职场和发展
zqx_71 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架
coderWangbuer1 小时前
基于springboot的高校招生系统(含源码+sql+视频导入教程+文档+PPT)
spring boot·后端·sql
攸攸太上1 小时前
JMeter学习
java·后端·学习·jmeter·微服务
Kenny.志1 小时前
2、Spring Boot 3.x 集成 Feign
java·spring boot·后端
惜.己1 小时前
javaScript基础(8个案例+代码+效果图)
开发语言·前端·javascript·vscode·css3·html5
sky丶Mamba2 小时前
Spring Boot中获取application.yml中属性的几种方式
java·spring boot·后端
什么鬼昵称2 小时前
Pikachu-csrf-CSRF(get)
前端·csrf
长天一色2 小时前
【ECMAScript 从入门到进阶教程】第三部分:高级主题(高级函数与范式,元编程,正则表达式,性能优化)
服务器·开发语言·前端·javascript·性能优化·ecmascript
NiNg_1_2342 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js