比公交车还便宜,萝卜快跑你怎么敢的呀?

429 阅读9分钟

萝卜快跑

萝卜快跑,是百度在 2021 年 8 月推出的,目的是通过百度多年积累的自动驾驶技术,加速全民无人化出行时代的到来

和常规的网约车不同,萝卜快跑打来的车辆,是没有司机的,乘客落座后,车子会自动规划路线,送乘客到目的地。

布局多年,萝卜快跑真正开始"破圈",被大家所知道,则是这两三个月的事情。

过去几个月,最出彩的萝卜在武汉

最开始,大概是 6 月中旬的时候,萝卜快跑突发性地有不少负面话题冲上热搜。

一时间,大量「萝卜快跑的车辆,经常引发交通拥堵,为市民的正常通勤带来困扰」这样的言论集中出现。

很快,萝卜的官号就发帖,指出当时的言论都是"水军故意抹黑",目前已配合公安成功侦破。

但你要说,这些负面舆论是不是真的清一色的"水军行为",我看未必。

有水军恶意抹黑或许不假,但据全网这么多网友的体验感受来看,萝卜快跑也确实有"过于谨慎"的问题。例如最高时速不超过 40 公里,遇到马路上的黑色塑料袋,会当成障碍物停下,直到塑料袋飘走...

从技术层面来看,这也很好理解,毕竟萝卜快跑现在做的是 L4 级别的自动驾驶,和我们日常用车中的 L2 辅助驾驶不是一个层级。

一个最简单的区别,在 L2 级别下发生事故,驾驶员负全部责任,系统仅是提供辅助,而在 L4 级别下发生事故,通常由车商或者系统供应商担责。

萝卜快跑跑得慢,但仍被广泛接受,自然也有其自身优点。

其中一个优点:相比于长期以「脾气火爆 + 驾驶彪悍」形象著称的武汉司机来说,萝卜快跑给大家提供了"i人选项",而且该选项从不绕路,比导航软件更知晓路况的拥堵情况,更能做出接近最优的路线选择。

但真正让萝卜快跑实现"绝杀"的是它的价格。

同样是 10 公里的路程,普通网约车价格在 18元30元 之间,而萝卜快跑的价格在 4元16元。

「萝卜快跑的上限价格」就比「普通网约车的下限价格」还低,而且还能 7*24 的接单,这还怎么比?

还有网友分享了自己 2 公里行程的萝卜快跑体验:"乘坐环境舒适,空间大,平时 10 元的打车费用,现在用萝卜快跑,只要 1.55 元,比公交车还便宜"。

不少网友直呼梦回当年滴滴和 Uber 的补贴大战,又一次感受到了打车自由。

诸多的叠加因素,百度进一步铺开了萝卜快跑在武汉的量。

据湖北发布官方信息称,如今武汉市以萝卜快跑为首的无人订单量迎来了爆发式增长。

单日单车峰值超 20 单,已可与出租车司机订单情况达到同一水平。

但随之带来的是"社会稳定性"的问题:网约车行业作为城市的铁人三项之一(另外两个是外卖配送和快递员),创造了无数的就业岗位,同时也是众多人失业后的"理想后路",现在连这个位置也要被机器抢走。

科技抢夺底层人饭碗,这引发了不少的社会恐慌。

甚至连什么「司机一觉醒来天塌了」这样的标题都出来了:

对此交通局回应:行业比较稳定 🤣🤣

我始终觉得,要以未来的眼光去看现在,现在的平台外卖员/网约车司机/电商快递员,在二十年前都不是能够承载这么多就业人数的岗位,甚至于都不存在。

以所谓的「抢人类饭碗」为由,来限制行业发展,是短浅的。

我们不能只指望央企国企带来创新性,只有像百度、阿里这种量级的民营企业发展好了,我们才有跟别人掰手腕的可能。

我对百度无感,甚至于没少嘲笑它在所有产品上都犯了「起个大早,赶个晚集」的错误。

但我也确实衷心希望萝卜快跑能成,这其实多少关乎于我们能否走出「人口红利」这一蜜糖罐,尤其是在出生率开始明显下降的如今,提高社会人效是一个科学的社会问题。

所谓的「行业集体下岗」这样的论调,我们在滴滴和 Uber 推出的时候就听过,现在得到的结果是,出租车司机不再是一个有门槛的行业,我们有了更多的就业,大家的出行方式更加科学;再往前一点,这样的言论在我国制造业自动化过程中,也听得不少,现在得到的结果是,我们在诸多行业的产能能够直接满足全球需求,Made in China 遍布全球。

所以别怕,只管拥抱变化。

或许在我们可以触摸到的未来,人工司机能够集体坐在空调房,远程接管这些路况复杂的自动驾驶效果不好的订单,花更少的力气来赚差不多的钱。

未来的事,谁知道呢,你又怎么看呢?

...

回归主题。

来一道和「百度一面」相关的题目。

题目描述

平台:LeetCode

题号:581

给你一个整数数组 nums,你需要找出一个连续子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。

请你找出符合题意的最短子数组,并输出它的长度。

示例 1:

输入:nums = [2,6,4,8,10,9,15]

输出:5

解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。

示例 2:

输入:nums = [1,2,3,4]

输出:0 

示例 3:

输入:nums = [1]

输出:0

提示:

  • 1<=nums.length<=1041 <= nums.length <= 10^4

  • 105<=nums[i]<=105-10^5 <= nums[i] <= 10^5

  • 进阶:你可以设计一个时间复杂度为 O(n)O(n) 的解决方案吗?

双指针 + 排序

最终目的是让整个数组有序,那么我们可以先将数组拷贝一份进行排序,然后使用两个指针 ij 分别找到左右两端第一个不同的地方,那么 [i,j][i, j] 这一区间即是答案。

Java 代码:

class Solution {
    public int findUnsortedSubarray(int[] nums) {
        int n = nums.length;
        int[] arr = nums.clone();
        Arrays.sort(arr);
        int i = 0, j = n - 1;
        while (i <= j && nums[i] == arr[i]) i++;
        while (i <= j && nums[j] == arr[j]) j--;
        return j - i + 1;
    }
}

C++ 代码:

class Solution {
public:
    int findUnsortedSubarray(vector<int>& nums) {
        int n = nums.size();
        vector<int> arr(nums);
        sort(arr.begin(), arr.end());
        int i = 0, j = n - 1;
        while (i <= j && nums[i] == arr[i]) ++i;
        while (i <= j && nums[j] == arr[j]) --j;
        return j - i + 1;
    }
};

Python 代码:

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        n = len(nums)
        arr = sorted(nums)
        i, j = 0, n - 1
        while i <= j and nums[i] ==arr[i]: 
            i += 1
        while i <= j and nums[j] == arr[j]: 
            j -= 1
        return j - i + 1

TypeScript 代码:

function findUnsortedSubarray(nums: number[]): number {
    const n: number = nums.length;
    const arr: number[] = Array.from(nums).sort((a, b) => a - b);
    let i: number = 0, j: number = n - 1;
    while (i <= j && nums[i] === arr[i]) i++;
    while (i <= j && nums[j] === arr[j]) j--;
    return j - i + 1;  
};
  • 时间复杂度:O(nlogn)O(n\log{n})
  • 空间复杂度:O(n)O(n)

双指针 + 线性扫描

另外一个做法是,我们把整个数组分成三段处理。

起始时,先通过双指针 ij 找到左右两次侧满足 单调递增 的分割点。

即此时 [0,i][0, i][j,n)[j, n) 满足升序要求,而中间部分 (i,j)(i, j) 不确保有序

然后我们对中间部分 [i,j][i, j] 进行遍历:

  • 发现 nums[x]<nums[i1]nums[x] < nums[i - 1]:由于对 [i,j][i, j] 部分进行排序后 nums[x]nums[x] 会出现在 nums[i1]nums[i - 1] 后,将不满足整体升序,此时我们需要调整分割点 ii 的位置;
  • 发现 nums[x]>nums[j+1]nums[x] > nums[j + 1]:由于对 [i,j][i, j] 部分进行排序后 nums[x]nums[x] 会出现在 nums[j+1]nums[j + 1] 前,将不满足整体升序,此时我们需要调整分割点 jj 的位置。

一些细节:在调整 ij 的时候,我们可能会到达数组边缘,这时候可以建立两个哨兵:数组左边存在一个足够小的数,数组右边存在一个足够大的数。

Java 代码:

class Solution {
    int MIN = -100005, MAX = 100005;
    public int findUnsortedSubarray(int[] nums) {
        int n = nums.length;
        int i = 0, j = n - 1;
        while (i < j && nums[i] <= nums[i + 1]) i++;
        while (i < j && nums[j] >= nums[j - 1]) j--;
        int l = i, r = j;
        int min = nums[i], max = nums[j];
        for (int u = l; u <= r; u++) {
            if (nums[u] < min) {
                while (i >= 0 && nums[i] > nums[u]) i--;
                min = i >= 0 ? nums[i] : MIN;
            }
            if (nums[u] > max) {
                while (j < n && nums[j] < nums[u]) j++;
                max = j < n ? nums[j] : MAX;
            }
        }
        return j == i ? 0 : (j - 1) - (i + 1) + 1;
    }
}

C++ 代码:

class Solution {
public:
    int MIN = -100005, MAX = 100005;
    int findUnsortedSubarray(vector<int>& nums) {
        int n = nums.size();
        int i = 0, j = n - 1;
        while (i < j && nums[i] <= nums[i + 1]) i++;
        while (i < j && nums[j] >= nums[j - 1]) j--;
        int l = i, r = j;
        int minv = nums[i], maxv = nums[j];
        for (int u = l; u <= r; ++u) {
            if (nums[u] < minv) {
                while (i >= 0 && nums[i] > nums[u]) i--;
                minv = i >= 0 ? nums[i] : MIN;
            }
            if (nums[u] > maxv) {
                while (j < n && nums[j] < nums[u]) j++;
                maxv = j < n ? nums[j] : MAX;
            }
        }
        return j == i ? 0 : (j - 1) - (i + 1) + 1;
    }
};

Python 代码:

class Solution:
    def findUnsortedSubarray(self, nums: List[int]) -> int:
        n, MIN, MAX = len(nums), -100005, 100005
        i, j = 0, n - 1
        while i < j and nums[i] <= nums[i + 1]:
            i += 1
        while i < j and nums[j] >= nums[j - 1]:
            j -= 1
        l, r = i, j
        minv, maxv = nums[i], nums[j]
        for u in range(l, r + 1):
            if nums[u] < minv:
                while i >= 0 and nums[i] > nums[u]:
                    i -= 1
                minv = MIN if i < 0 else nums[i]
            if nums[u] > maxv:
                while j < n and nums[j] < nums[u]:
                    j += 1
                maxv = MAX if j >= n else nums[j]
        return 0 if j == i else (j - 1) - (i + 1) + 1

TypeScript 代码:

function findUnsortedSubarray(nums: number[]): number {
    const n: number = nums.length, MIN: number = -100005, MAX: number = 100005;
    let i: number = 0, j: number = n - 1;
    while (i < j && nums[i] <= nums[i + 1]) i++;
    while (i < j && nums[j] >= nums[j - 1]) j--;
    const l = i, r = j;
    let minv = nums[i], maxv = nums[j];
    for (let u: number = l; u <= r; u++) {
        if (nums[u] < minv) {
            while (i >= 0 && nums[i] > nums[u]) i--;
            minv = i >= 0 ? nums[i] : MIN;
        }
        if (nums[u] > maxv) {
            while (j < n && nums[j] < nums[u]) j++;
            maxv = j < n ? nums[j] : MAX;
        }
    }
    return j === i ? 0 : (j - 1) - (i + 1) + 1;
};
  • 时间复杂度:O(n)O(n)
  • 空间复杂度:O(1)O(1)