送外卖,3年102万,先别着急破防

外卖小哥,三年百万

刚过去不久的周末,最火的一则新闻是上海,外卖小哥 3 年掙了 102 万

能上热搜,说明这个收入,还是明显超出了群众普遍认知的。

我们知道,通常诸如「外卖/快递/网约车」这样的职业,强调一个多劳多得。

但一般内心都会给他们框定一个认知上的大概上界,例如一个月再怎么也不会超过 2w。

毕竟再多劳多得,也是一天 24 小时,一个人一双手一双腿。

3 年 102 万,平均下来一个月 2.8 万。

乍一听,会以为是个明显存在逻辑漏洞的人造新闻。

如果再继续套用常规思路去理解,会发现即使外卖小哥 3 年来全年无休,一天 24 小时,也掙不了 102 万。

既然再用外行人思维分析无果,不然先纠正外卖小哥单月的收入上界的认识。

利用搜索引擎,我们发现好几年前就有「送外卖,月入2-3万」的新闻,且这些新闻的主角(外卖小哥)所在地也并不局限在一线城市。

因此,2.8 万,在单月收入里面,可以算作是一个在全国范围内,行业内公认的收入天花板水平,不至于是一个不可能完成的任务。

然后再来评估「月收入持续达到天花板水平」的难度,便可得知新闻本身的合理程度。

注意:这里强调是合理程度,而非真实程度,在不超出合理程度范围的事件,我们无法不依靠更多的信息去判别真伪。

接着分析,收入持续维持高水平的难度。

由于 3 年 102 万的外卖小哥,工作所在地是上海,上六休一,日均工作 18 小时

那么注定了其存在一些客观优势:

  • 相比于其他城市,所在地送餐单价更高;
  • 3 年里面包含了疫情封城的特殊时期;
  • 长期的上六休一,大概率覆盖了绝大多数的恶劣天气,恶劣天气有额外补贴;
  • 超长的日均工作时间,大概率覆盖了有补贴的送餐时间段;

这些客观条件的存在,使得「持续摸到全国级外卖行业收入天花板」的难度,相对低了一点,至少不是网友想象中的绝无可能。

有自媒体把该新闻和《买彩票,10万中2.2亿》的事情放一起,说这是挑战网友智商年度事件中的卧龙凤雏。

说实话,这有点侮辱外卖小哥了。

是否真实,永远不会有一个准确的说法,但仅从合理程度来看,这俩压根不是一个量级。

我猜测这些自媒体,既不了解福利彩票现有机制,说不出来为什么发生「10万2.2亿」实际是国有公证制度问题导致的结果;也没有了解外卖行业的基础现状,只会套用自己日常点外卖的配送费多少和送餐时长的错误了解,就动手写文案了。

...

分析完事件的合理程度,习惯性的,我还想了解一下新闻的报道倾向性。

毕竟再大的事件,也不都必然能够引起全国热议。

反过来说,那些能够引起全国热议的事件,背后必然有神秘力量使然。

注意,即使只是任其发酵,那也是力量的体现。

要看清新闻报道的倾向性,可以重点看原始报道(通常没有太多加工内容)发布之后的官媒内容。

于是我释怀的笑了。

我不知道这些突如其来的流量,会不会让外卖小哥转行成为演员或带货主播。

目前这些"正能量"报道/采访,看起来至少能外卖小哥带薪多休息几天。

后续怎么发展,就不多猜测了。

...

回到主线。

实在没找到送 🍚 的题目,一起送 📦 吧。

题目描述

平台:LeetCode

题号:1011

传送带上的包裹必须在 D 天内从一个港口运送到另一个港口。

传送带上的第 i 个包裹的重量为 <math xmlns="http://www.w3.org/1998/Math/MathML"> w e i g h t s [ i ] weights[i] </math>weights[i]。

每一天,我们都会按给出重量的顺序往传送带上装载包裹。

我们装载的重量不会超过船的最大运载重量。

返回能在 D 天内将传送带上的所有包裹送达的船的最低运载能力。

示例 1:

scss 复制代码
输入:weights = [1,2,3,4,5,6,7,8,9,10], D = 5

输出:15

解释:
船舶最低载重 15 就能够在 5 天内送达所有包裹,如下所示:
第 1 天:1, 2, 3, 4, 5
第 2 天:6, 7
第 3 天:8
第 4 天:9
第 5 天:10

请注意,货物必须按照给定的顺序装运,因此使用载重能力为 14 的船舶并将包装分成 (2, 3, 4, 5), (1, 6, 7), (8), (9), (10) 是不允许的。 

示例 2:

ini 复制代码
输入:weights = [3,2,2,4,1,4], D = 3

输出:6

解释:
船舶最低载重 6 就能够在 3 天内送达所有包裹,如下所示:
第 1 天:3, 2
第 2 天:2, 4
第 3 天:1, 4

示例 3:

ini 复制代码
输入:weights = [1,2,3,1,1], D = 4

输出:3

解释:
第 1 天:1
第 2 天:2
第 3 天:3
第 4 天:1, 1

提示:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = D < = w e i g h t s . l e n g t h < = 5 × 1 0 4 1 <= D <= weights.length <= 5 \times 10^4 </math>1<=D<=weights.length<=5×104
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = w e i g h t s [ i ] < = 500 1 <= weights[i] <= 500 </math>1<=weights[i]<=500

二分解法(精确边界)

假定「D 天内运送完所有包裹的最低运力」为 ans,那么在以 ans 为分割点的数轴上具有「二段性」:

  • 数值范围在 <math xmlns="http://www.w3.org/1998/Math/MathML"> ( − ∞ , a n s ) (-\infty, ans) </math>(−∞,ans) 的运力必然「不满足」 D 天内运送完所有包裹的要求
  • 数值范围在 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ a n s , + ∞ ) [ans, +\infty) </math>[ans,+∞) 的运力必然「满足」 D天内运送完所有包裹的要求

我们可以通过「二分」来找到恰好满足 D天内运送完所有包裹的分割点 ans

接下来我们要确定二分的范围,由于不存在包裹拆分的情况,考虑如下两种边界情况:

  • 理论最低运力:只确保所有包裹能够被运送,自然也包括重量最大的包裹,此时理论最低运力为 maxmax 为数组 weights 中的最大值
  • 理论最高运力:使得所有包裹在最短时间(一天)内运送完成,此时理论最高运力为 sumsum 为数组 weights 的总和

由此,我们可以确定二分的范围为 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ m a x , s u m ] [max, sum] </math>[max,sum]。

Java 代码:

Java 复制代码
class Solution {
    public int shipWithinDays(int[] weights, int days) {
        int max = 0, sum = 0;
        for (int w : weights) {
            max = Math.max(max, w);
            sum += w;
        }
        int l = max, r = sum;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(weights, mid, days)) r = mid;
            else l = mid + 1;
        }
        return r;
    }
    boolean check(int[] weights, int t, int days) {
        int n = weights.length, cnt = 1;
        for (int i = 1, sum = weights[0]; i < n; sum = 0, cnt++) {
            while (i < n && sum + weights[i] <= t) sum += weights[i++];
        }
        return cnt - 1 <= days;
    }
}

C++ 代码:

C++ 复制代码
class Solution {
public:
    int shipWithinDays(vector<int>& weights, int days) {
        int maxv = 0, sum = 0;
        for (int w : weights) {
            maxv = max(maxv, w);
            sum += w;
        }
        int l = maxv, r = sum;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(weights, mid, days)) r = mid;    
            else l = mid + 1;
        }
        return r;
    }
    bool check(vector<int>& weights, int t, int days) {
        int n = weights.size(), cnt = 1;
        for (int i = 1, sum = weights[0]; i < n; sum = 0, cnt++) {
            while (i < n && sum + weights[i] <= t) sum += weights[i++];
        }
        return cnt - 1 <= days;
    }
};

Python 代码:

Python 复制代码
class Solution:
    def shipWithinDays(self, weights: List[int], days: int) -> int:
        def check(weights: List[int], t: int, days: int) -> bool:
            n, cnt = len(weights), 1
            i, sumv = 1, weights[0]
            while i < n:
                while i < n and sumv + weights[i] <= t:
                    sumv += weights[i]
                    i += 1
                cnt += 1
                sumv = 0
            return cnt - 1 <= days

        maxv, sumv = max(weights), sum(weights)
        l, r = maxv, sumv
        while l < r:
            mid = l + r >> 1
            if check(weights, mid, days):
                r = mid
            else:
                l = mid + 1
        return r

TypeScript 代码:

TypeScript 复制代码
function shipWithinDays(weights: number[], days: number): number {
    const check = function(weights: number[], t: number, days: number): boolean {
        let n = weights.length, cnt = 1;
        for (let i = 1, sum = weights[0]; i < n; sum = 0, cnt++) {
            while (i < n && sum + weights[i] <= t) sum += weights[i++];
        }
        return cnt - 1 <= days;
    }
    let maxv = 0, sumv = 0;
    for (const w of weights) {
        maxv = Math.max(maxv, w);
        sumv += w;
    }
    let l = maxv, r = sumv;
    while (l < r) {
        const mid = l + r >> 1;
        if (check(weights, mid, days)) r = mid;
        else l = mid + 1;
    }
    return r;
};
  • 时间复杂度:二分范围为 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ m a x , s u m ] [max, sum] </math>[max,sum],check 函数的复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n)。整体复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n log ⁡ ( ∑ i = 0 n − 1 w s [ i ] ) ) O(n\log({\sum_{i= 0}^{n - 1}ws[i]})) </math>O(nlog(∑i=0n−1ws[i]))
  • 空间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( 1 ) O(1) </math>O(1)

二分解法(粗略边界)

当然,一个合格的「二分范围」只需要确保包含分割点 ans 即可。因此我们可以利用数据范围来确立粗略的二分范围(从而少写一些代码):

  • 利用运力必然是正整数,从而确定左边界为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1
  • 根据 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 ⩽ D ⩽ w e i g h t s . l e n g t h ⩽ 50000 1 \leqslant D \leqslant weights.length \leqslant 50000 </math>1⩽D⩽weights.length⩽50000 和 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 ⩽ w e i g h t s [ i ] ⩽ 500 1 \leqslant weights[i] \leqslant 500 </math>1⩽weights[i]⩽500,从而确定右边界为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 e 8 1e8 </math>1e8

PS. 由于二分查找具有折半效率,因此「确立粗略二分范围」不会比「通过循环取得精确二分范围」效率低。

Java 代码:

Java 复制代码
class Solution {
    public int shipWithinDays(int[] weights, int days) {
        int l = 1, r = (int)1e8;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(weights, mid, days)) r = mid;    
            else l = mid + 1;
        }
        return r;
    }
    boolean check(int[] weights, int t, int days) {
        if (weights[0] > t) return false;
        int n = weights.length, cnt = 1;
        for (int i = 1, sum = weights[0]; i < n; sum = 0, cnt++) {
            if (weights[i] > t) return false;
            while (i < n && sum + weights[i] <= t) sum += weights[i++];
        }
        return cnt - 1 <= days;
    }
}

C++ 代码:

C++ 复制代码
class Solution {
public:
    int shipWithinDays(vector<int>& weights, int days) {
        int l = 1, r = 1e8;
        while (l < r) {
            int mid = l + r >> 1;
            if (check(weights, mid, days)) r = mid;    
            else l = mid + 1;
        }
        return r;
    }
    bool check(vector<int>& weights, int t, int days) {
        if (weights[0] > t) return false;
        int n = weights.size(), cnt = 1;
        for (int i = 1, sum = weights[0]; i < n; sum = 0, cnt++) {
            if (weights[i] > t) return false;
            while (i < n && sum + weights[i] <= t) sum += weights[i++];
        }
        return cnt - 1 <= days;
    }
};

Python 代码:

Python 复制代码
class Solution:
    def shipWithinDays(self, weights: List[int], days: int) -> int:
        def check(weights: List[int], t: int, days: int) -> bool:
            if weights[0] > t: return False
            n, cnt = len(weights), 1
            i, sumv = 1, weights[0]
            while i < n:
                if weights[i] > t: return False
                while i < n and sumv + weights[i] <= t:
                    sumv += weights[i]
                    i += 1
                cnt += 1
                sumv = 0
            return cnt - 1 <= days

        l, r = 1, 10**8
        while l < r:
            mid = l + r >> 1
            if check(weights, mid, days):
                r = mid
            else:
                l = mid + 1
        return r

TypeScript 代码:

TypeScript 复制代码
function shipWithinDays(weights: number[], days: number): number {
    const check = function(weights: number[], t: number, days: number): boolean {
        if (weights[0] > t) return false;
        let n = weights.length, cnt = 1;
        for (let i = 1, sum = weights[0]; i < n; sum = 0, cnt++) {
            if (weights[i] > t) return false;
            while (i < n && sum + weights[i] <= t) sum += weights[i++];
        }
        return cnt - 1 <= days;
    }
    let l = 0, r = 1e8;
    while (l < r) {
        const mid = l + r >> 1;
        if (check(weights, mid, days)) r = mid;
        else l = mid + 1;
    }
    return r;
};
  • 时间复杂度:二分范围为 <math xmlns="http://www.w3.org/1998/Math/MathML"> [ 1 , 1 e 8 ] [1, 1e8] </math>[1,1e8],check 函数的复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n)。整体复杂度为 <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n log ⁡ 1 e 8 ) O(n\log{1e8}) </math>O(nlog1e8)
  • 空间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( 1 ) O(1) </math>O(1)

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

欢迎关注,明天见。

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

相关推荐
灯火不休ᝰ几秒前
前端处理pdf文件流,展示pdf
前端·pdf
智践行3 分钟前
Trae开发实战之转盘小程序
前端·trae
最新资讯动态8 分钟前
DialogHub上线OpenHarmony开源社区,高效开发鸿蒙应用弹窗
前端
lvbb6618 分钟前
框架修改思路
前端·javascript·vue.js
树上有只程序猿20 分钟前
Java程序员需要掌握的技术
前端
雷渊23 分钟前
深入分析Spring的事务隔离级别及实现原理
java·后端·面试
从零开始学安卓23 分钟前
Kotlin(三) 协程
前端
阿镇吃橙子27 分钟前
一些手写及业务场景处理问题汇总
前端·算法·面试
庸俗今天不摸鱼27 分钟前
【万字总结】前端全方位性能优化指南(九)——FSP(First Screen Paint)像素级分析、RUM+合成监控、Lighthouse CI
前端·性能优化