华为面试题,连续出了三年!

写在前面

据说,这是一道被华为 202120222023 都出过的题目 🤣

华为是「卷」的发明者,但不是「内卷」发明者,毕竟只有华为是实打实的给加班费。

这么卷的公司,怎么也不更新一下题库。

难道没人做出来就不用考虑换题?再这么搞可就成为背诵材料了 🤣

题目描述

平台:LeetCode

题号:871

汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。

沿途有加油站,每个 station[i] 代表一个加油站,它位于出发位置东面 station[i][0] 英里处,并且有 station[i][1] 升汽油。

假设汽车油箱的容量是无限的,其中最初有 startFuel 升燃料。它每行驶 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1 英里就会用掉 <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 1 </math>1 升汽油。

当汽车到达加油站时,它可能停下来加油,将所有汽油从加油站转移到汽车中。

为了到达目的地,汽车所必要的最低加油次数是多少?如果无法到达目的地,则返回 <math xmlns="http://www.w3.org/1998/Math/MathML"> − 1 -1 </math>−1 。

注意:如果汽车到达加油站时剩余燃料为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 0 </math>0,它仍然可以在那里加油。如果汽车到达目的地时剩余燃料为 <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 0 </math>0,仍然认为它已经到达目的地。

示例 1:

ini 复制代码
输入:target = 1, startFuel = 1, stations = []

输出:0

解释:我们可以在不加油的情况下到达目的地。

示例 2:

lua 复制代码
输入:target = 100, startFuel = 1, stations = [[10,100]]

输出:-1

解释:我们无法抵达目的地,甚至无法到达第一个加油站。

示例 3:

lua 复制代码
输入:target = 100, startFuel = 10, stations = [[10,60],[20,30],[30,30],[60,40]]

输出:2

解释:
我们出发时有 10 升燃料。
我们开车来到距起点 10 英里处的加油站,消耗 10 升燃料。将汽油从 0 升加到 60 升。
然后,我们从 10 英里处的加油站开到 60 英里处的加油站(消耗 50 升燃料),
并将汽油从 10 升加到 50 升。然后我们开车抵达目的地。
我们沿途在1两个加油站停靠,所以返回 2 。

提示:

  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = t a r g e t , s t a r t F u e l , s t a t i o n s [ i ] [ 1 ] < = 1 0 9 1 <= target, startFuel, stations[i][1] <= 10^9 </math>1<=target,startFuel,stations[i][1]<=109
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 0 < = s t a t i o n s . l e n g t h < = 500 0 <= stations.length <= 500 </math>0<=stations.length<=500
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = p o s i t i o n i < p o s i t i o n i + 1 < t a r g e t 1 <= position_{i} < position_{i+1} < target </math>1<=positioni<positioni+1<target
  • <math xmlns="http://www.w3.org/1998/Math/MathML"> 1 < = f u e l i < 1 0 9 1 <= fuel_{i} < 10^9 </math>1<=fueli<109

贪心 + 优先队列(堆)

我们可以模拟行进过程,使用 n 代表加油站总个数,idx 代表经过的加油站下标,使用 remain 代表当前有多少油(起始有 remain = startFuel),loc 代表走了多远,ans 代表答案(至少需要的加油次数)。

只要 loc < target,代表还没到达(经过)目标位置,我们可以继续模拟行进过程。

每次将 remain 累加到 loc 中,含义为使用完剩余的油量,可以去到的最远距离,同时将所在位置 stations[idx][0] <= loc 的加油站数量加入优先队列(大根堆,根据油量排倒序)中。

再次检查是否满足 loc < target(下次循环),此时由于清空了剩余油量 remain,我们尝试从优先队列(大根堆)中取出过往油量最大的加油站并进行加油(同时对加油次数 ans 进行加一操作)。

使用新的剩余油量 remain 重复上述过程,直到满足 loc >= target 或无油可加。

容易证明该做法的正确性:同样是消耗一次加油次数,始终选择油量最大的加油站进行加油,可以确保不存在更优的结果。

Java 代码:

Java 复制代码
class Solution {
    public int minRefuelStops(int target, int startFuel, int[][] stations) {
        PriorityQueue<Integer> q = new PriorityQueue<>((a,b)->b-a);
        int n = stations.length, idx = 0;
        int remain = startFuel, loc = 0, ans = 0;
        while (loc < target) {
            if (remain == 0) {
                if (!q.isEmpty() && ++ans >= 0) remain += q.poll();
                else return -1;
            }
            loc += remain; remain = 0;
            while (idx < n && stations[idx][0] <= loc) q.add(stations[idx++][1]);
        }
        return ans;
    }
}

C++ 代码:

C++ 复制代码
class Solution {
public:
    int minRefuelStops(int target, int startFuel, vector<vector<int>>& stations) {
        priority_queue<int> q;
        int n = stations.size(), idx = 0;
        int remain = startFuel, loc = 0, ans = 0;
        while (loc < target) {
            if (remain == 0) {
                if (!q.empty() && ++ans >= 0) {
                    remain += q.top();
                    q.pop();
                } else {
                    return -1;
                }
            }
            loc += remain; remain = 0;
            while (idx < n && stations[idx][0] <= loc) q.push(stations[idx++][1]);
        }
        return ans;
    }
};

Python 代码:

Python 复制代码
class Solution:
    def minRefuelStops(self, target: int, startFuel: int, stations: List[List[int]]) -> int:
        q = []
        n, idx = len(stations), 0
        remain, loc, ans = startFuel, 0, 0
        while loc < target:
            if remain == 0:
                if q:
                    ans += 1
                    remain += -heappop(q)
                else:
                    return -1
            loc, remain = loc + remain, 0
            while idx < n and stations[idx][0] <= loc:
                heappush(q, -stations[idx][1])
                idx += 1
        return ans
  • 时间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n log ⁡ n ) O(n\log{n}) </math>O(nlogn)
  • 空间复杂度: <math xmlns="http://www.w3.org/1998/Math/MathML"> O ( n ) O(n) </math>O(n)

总结

贪心 + 优先队列(堆)其实是一类问题。

出现频率仅次于「贪心 + 排序」的搭配。

两种做法本质都是在决策过程中,按"优先取最值"的方式进行贪心。

后面会起一个专门的「贪心」专题来讲此类题,欢迎关注。

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

相关推荐
passerby60611 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX1 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了1 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅1 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅1 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法2 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate
崔庆才丨静觅2 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment2 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅2 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊2 小时前
jwt介绍
前端