likes
comments
collection
share

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

作者站长头像
站长
· 阅读数 5

腾讯年终奖

什么是真正的好公司?

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

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

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

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:

输入: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:

输入: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 的分发方案。

提示:

  • 2<=cs.length<=82 <= cs.length <= 82<=cs.length<=8
  • 1<=cs[i]<=1051 <= cs[i] <= 10^51<=cs[i]<=105
  • 2<=k<=cs.length2 <= k <= cs.length2<=k<=cs.length

状压 DP

定义 f[i][s]f[i][s]f[i][s] 为考虑前 iii 个人,对 cs 的分配情况为 s 时的最小不公平程度。

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

初始化只有 f[0][0]=0f[0][0] = 0f[0][0]=0,其余均为正无穷 0x3f3f3f3f

不失一般性考虑 f[i][s]f[i][s]f[i][s] 该如何计算,通过枚举第 iii 个小朋友所分配到的饼干情况 ps 的子集)进行转移:若第 iii 个小朋友分配到的饼干情况为 p,则此前 i−1i - 1i1 个小朋友分配到饼干情况为 s−ps - psp,前 i−1i - 1i1 个小朋友的最小不公平程度为 f[i−1][s−p]f[i - 1][s - p]f[i1][sp],当前第 iii 个小朋友的不公平程度为 g[p]g[p]g[p],两者中最大值可用于更新 f[i][s]f[i][s]f[i][s]

f[i][s]=min⁡(f[i][s],max⁡(f[i−1][s−p],g[p])),p⊆sf[i][s] = \min(f[i][s], \max(f[i - 1][s - p], g[p])), p \subseteq sf[i][s]=min(f[i][s],max(f[i1][sp],g[p])),ps

最终 f[k][2n−1]f[k][2^n - 1]f[k][2n1] 即是答案。

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 代码:

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++ 代码:

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 代码:

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 长度记为 nnn,状态数量记为 m=2nm = 2^nm=2n,预处理复杂度为 O(n×m)O(n \times m)O(n×m)DP 过程需要枚举二进制长度为 nnn 的所有子集的子集,复杂度为 O(3n)O(3^n)O(3n)DP 过程复杂度为 O(k×3n)O(k \times 3^n)O(k×3n)。整体复杂度为 O(k×3n)O(k \times 3^n)O(k×3n)
  • 空间复杂度:O(k×m)O(k \times m)O(k×m)

小答疑

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

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

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

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

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

  1. 0x3f3f3f3f222 不会发生溢出
  2. 0x3f3f3f3f 每字节都是 0x3f,因此 C++ 可以直接通过 memset(array, 0x3f, sizeof(array)) 的方式来得到一个初始值为无穷大的数组,而无需使用循环赋值的方式来做

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

欢迎关注,明天见。

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