美团 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 分钟前
前端八股文面经大全:腾讯前端暑期提前批一、二、三面面经(上)(2026-03-04)·面经深度解析
前端
ErizJ3 分钟前
面试 | Kafka
面试·kafka
江湖十年6 分钟前
AI Agent 生态再添一员,Kratos 带着他的武器 Blades 走来了!
人工智能·后端·go
l软件定制开发工作室6 分钟前
Spring开发系列教程(32)——Spring Boot开发
java·spring boot·后端·spring
嘉琪0018 分钟前
Day4 完整学习包(this 指向)——2026 0313
前端·javascript·学习
前端小菜鸟也有人起8 分钟前
Vue3父子组件通信方法总结
前端·javascript·vue.js
peachSoda711 分钟前
小程序图片加载优化方案
前端·微信小程序·小程序
iPadiPhone15 分钟前
性能优化的“快车道”:Spring @Async 注解深度原理与大厂实战
java·后端·spring·面试·性能优化