美团 2025 届校招开始了,岗位 and 原题抢先看!!

美团校招 - 启动

前几天我们写了 阿里巴巴 开启 2025 届的校招计划,其实比阿里巴巴更早的是 美团

你看,互联网大厂启动校招计划尚且争先恐后,你还有什么理由不马上行动?!

先来大概浏览一下本次校招「技术类」相关的常规岗位:

几乎所有岗位都可以 base 北京,少部分可以选择 上海 和 成都 。

然后再详细列举一下于公主号读者相关性更高的几个岗位:

除了这些常规校招岗位,美团本次还延续了「北斗计划」的开展。

招聘岗位都是一些细分领域的算法岗。

...

回归主线。

来做一道和「美团」相关的一面算法原题。

题目描述

平台:LeetCode

题号:808

AB 两种类型 的汤,一开始每种类型的汤有 n 毫升。

有四种分配操作:

  1. 提供 100ml 的 汤A 和 0ml 的 汤B 。
  2. 提供 75ml 的 汤A 和 25ml 的 汤B 。
  3. 提供 50ml 的 汤A 和 50ml 的 汤B 。
  4. 提供 25ml 的 汤A 和 75ml 的 汤B 。

当我们把汤分配给某人之后,汤就没有了。

每个回合,我们将从四种概率同为 0.25 的操作中进行分配选择。

如果汤的剩余量不足以完成某次操作,我们将尽可能分配。

当两种类型的汤都分配完时,停止操作。

注意 不存在先分配 100 ml 汤B 的操作。

需要返回的值:汤A 先分配完的概率 + 汤A和汤B 同时分配完的概率 / 2。

返回值在正确答案 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 0 − 5 10^{-5} </math>10−5 的范围内将被认为是正确的。

示例 1:

less 复制代码
输入: n = 50

输出: 0.62500

解释:如果我们选择前两个操作,A 首先将变为空。
对于第三个操作,A 和 B 会同时变为空。
对于第四个操作,B 首先将变为空。
所以 A 变为空的总概率加上 A 和 B 同时变为空的概率的一半是 0.25 *(1 + 1 + 0.5 + 0)= 0.625。

示例 2:

ini 复制代码
输入: n = 100

输出: 0.71875

提示:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 < = n < = 1 0 9 0 <= n <= 10^9 </math>0<=n<=109

数学 + 动态规划

四种分配方式都是 <math xmlns="http://www.w3.org/1998/Math/MathML"> 25 25 </math>25 的倍数,因此我们可以将 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 进行除以 <math xmlns="http://www.w3.org/1998/Math/MathML"> 25 25 </math>25 上取整的缩放操作,并将四类操作等价成:

  1. 提供 4ml 的 汤A 和 0ml 的 汤B 。
  2. 提供 3ml 的 汤A 和 1ml 的 汤B 。
  3. 提供 2ml 的 汤A 和 2ml 的 汤B 。
  4. 提供 1ml 的 汤A 和 3ml 的 汤B 。

定义 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ i ] [ j ] f[i][j] </math>f[i][j] 为 汤A 剩余 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 毫升,汤B 剩余 <math xmlns="http://www.w3.org/1998/Math/MathML"> j j </math>j 毫升时的最终概率( <math xmlns="http://www.w3.org/1998/Math/MathML"> 概率 = 汤 A 先分配完的概率 + 汤 A 和汤 B 同时分配完的概率 × 0.5 概率 = 汤A先分配完的概率 + 汤A和汤B同时分配完的概率 \times 0.5 </math>概率=汤A先分配完的概率+汤A和汤B同时分配完的概率×0.5)。

最终答案为 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ n ] [ n ] f[n][n] </math>f[n][n] 为最终答案,考虑任意项存在为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 0 </math>0 情况时的边界情况:

  • 若 <math xmlns="http://www.w3.org/1998/Math/MathML"> i = 0 i = 0 </math>i=0 且 <math xmlns="http://www.w3.org/1998/Math/MathML"> j = 0 j = 0 </math>j=0,结果为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 + 1 2 = 1 2 0 + \frac{1}{2} = \frac{1}{2} </math>0+21=21,即有 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ 0 ] [ 0 ] = 0.5 f[0][0] = 0.5 </math>f[0][0]=0.5
  • 若 <math xmlns="http://www.w3.org/1998/Math/MathML"> i = 0 i = 0 </math>i=0 且 <math xmlns="http://www.w3.org/1998/Math/MathML"> j > 0 j > 0 </math>j>0,结果为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 + 0 = 1 1 + 0 = 1 </math>1+0=1,即有 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ 0 ] [ X ] = 1 f[0][X] = 1 </math>f[0][X]=1,其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> X > 1 X > 1 </math>X>1
  • 若 <math xmlns="http://www.w3.org/1998/Math/MathML"> i > 0 i > 0 </math>i>0 且 <math xmlns="http://www.w3.org/1998/Math/MathML"> j = 0 j = 0 </math>j=0,结果为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 + 0 = 0 0 + 0 = 0 </math>0+0=0,即有 <math xmlns="http://www.w3.org/1998/Math/MathML"> f [ X ] [ 0 ] = 0 f[X][0] = 0 </math>f[X][0]=0,其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> X > 1 X > 1 </math>X>1

其余一般情况为 <math xmlns="http://www.w3.org/1998/Math/MathML"> i i </math>i 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> j j </math>j 均不为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 0 </math>0,由于四类操作均为等概率,结合题意和状态定义可知:
<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"> f [ i ] [ j ] = 1 4 × ( f [ i − 4 ] [ j ] + f [ i − 3 ] [ j − 1 ] + f [ i − 2 ] [ j − 2 ] + f [ i − 1 ] [ j − 3 ] ) f[i][j] = \frac{1}{4} \times (f[i - 4][j] + f[i - 3][j - 1] + f[i - 2][j - 2] + f[i - 1][j - 3]) </math>f[i][j]=41×(f[i−4][j]+f[i−3][j−1]+f[i−2][j−2]+f[i−1][j−3])

由于 <math xmlns="http://www.w3.org/1998/Math/MathML"> n = 1 e 9 n = 1e9 </math>n=1e9,即使进行了除 <math xmlns="http://www.w3.org/1998/Math/MathML"> 25 25 </math>25 的缩放操作,过多的状态数仍会导致 TLE

此时需要利用「返回值在正确答案 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 0 − 5 10^{-5} </math>10−5 的范围内将被认为是正确的」来做优化(一下子不太好想到):由于四类操作均是等概率,单个回合期望消耗汤 A 的量为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 2.5 2.5 </math>2.5,消耗汤 B 的量为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1.5 1.5 </math>1.5。

因此当 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 足够大,操作回合足够多,汤 A 将有较大的概率结束分配,即当 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 足够大,概率值会趋向于 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1。

我们考虑多大的 <math xmlns="http://www.w3.org/1998/Math/MathML"> n n </math>n 能够配合精度误差 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 0 − 5 10^{-5} </math>10−5 来减少计算量:一个可行的操作是利用上述的 DP 思路 + 二分的方式找到符合精度要求的验算值(不超过 <math xmlns="http://www.w3.org/1998/Math/MathML"> 200 200 </math>200)。

Java 代码:

Java 复制代码
class Solution {
    public double soupServings(int n) {
        n = Math.min(200, (int) Math.ceil(n / 25.0));
        double[][] f = new double[n + 10][n + 10];
        f[0][0] = 0.5;
        for (int j = 1; j <= n; j++) f[0][j] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                double a = f[Math.max(i - 4, 0)][j], b = f[Math.max(i - 3, 0)][Math.max(j - 1, 0)];
                double c = f[Math.max(i - 2, 0)][Math.max(j - 2, 0)], d = f[Math.max(i - 1, 0)][Math.max(j - 3, 0)];
                f[i][j] = 0.25 * (a + b + c + d);
            }
        }
        return f[n][n];
    }
}

C++ 代码:

C++ 复制代码
class Solution {
public:
    double soupServings(int n) {
        n = min(200, (int)ceil(n / 25.0));
        vector<vector<double>> f(n + 10, vector<double>(n + 10, 0));
        f[0][0] = 0.5;
        for (int j = 1; j <= n; ++j) f[0][j] = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                double a = f[max(i - 4, 0)][j], b = f[max(i - 3, 0)][max(j - 1, 0)];
                double c = f[max(i - 2, 0)][max(j - 2, 0)], d = f[max(i - 1, 0)][max(j - 3, 0)];
                f[i][j] = 0.25 * (a + b + c + d);
            }
        }
        return f[n][n];
    }
};

Python 代码:

Python 复制代码
class Solution:
    def soupServings(self, n: int) -> float:
        n = min(200, math.ceil(n / 25))
        f = [[0] * (n + 10) for _ in range(n + 10)]
        f[0][0] = 0.5
        for j in range(1, n + 10):
            f[0][j] = 1
        for i in range(1, n + 1):
            for j in range(1, n + 1):
                a, b = f[max(i - 4, 0)][j], f[max(i - 3, 0)][max(j - 1, 0)]
                c, d = f[max(i - 2, 0)][max(j - 2, 0)], f[max(i - 1, 0)][max(j - 3, 0)]
                f[i][j] = 0.25 * (a + b + c + d)
        return f[n][n]

TypeScript 代码:

TypeScript 复制代码
function soupServings(n: number): number {
    n = Math.min(200, Math.ceil(n / 25.0));
    const f: number[][] = Array(n + 10).fill(0).map(() => Array(n + 10).fill(0));
    f[0][0] = 0.5;
    for (let j = 1; j <= n; j++) f[0][j] = 1;
    for (let i = 1; i <= n; i++) {
        for (let j = 1; j <= n; j++) {
            let a = f[Math.max(i - 4, 0)][j], b = f[Math.max(i - 3, 0)][Math.max(j - 1, 0)];
            let c = f[Math.max(i - 2, 0)][Math.max(j - 2, 0)], d = f[Math.max(i - 1, 0)][Math.max(j - 3, 0)];
            f[i][j] = 0.25 * (a + b + c + d);
        }
    }
    return f[n][n]; 
};
  • 时间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( m 2 ) O(m^2) </math>O(m2),其中 <math xmlns="http://www.w3.org/1998/Math/MathML"> m = 200 m = 200 </math>m=200 为验算值
  • 空间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( m 2 ) O(m^2) </math>O(m2)

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

欢迎关注,明天见。

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

相关推荐
我会冲击波2 分钟前
告别flag与status:如何为你的布尔值(boolean)变量优雅命名?
java·后端
浏览器API调用工程师_Taylor3 分钟前
自动化重复任务:从手动操作到效率飞跃
前端·javascript·爬虫
工藤学编程7 分钟前
分库分表之实战-sharding-JDBC水平分库+分表后:查询与删除操作实战
数据库·spring boot·后端·sql·mysql
赵润凤12 分钟前
Vue 高级视频播放器实现指南
前端
码出极致19 分钟前
Redisson 分布式锁自动续期机制解析
后端
小塵20 分钟前
【DeepSeek 聊天】五分钟部署本地 DeepSeek
人工智能·后端·deepseek
土拨鼠的旅程22 分钟前
Go map 源码详解【2】—— map 插入
后端
泊浮目26 分钟前
生产级Rust代码品鉴(一)RisingWave一条SQL到运行的流程
大数据·后端·rust
FogLetter26 分钟前
从原生JS事件到React事件机制:深入理解前端事件处理
前端·javascript·react.js
小公主39 分钟前
如何利用闭包封装私有变量?掌握防抖、节流与 this 问题的巧妙解决方案
前端