LeetCode 题解工作台

统计所有可行路径

给你一个 互不相同 的整数数组,其中 locations[i] 表示第 i 个城市的位置。同时给你 start , finish 和 fuel 分别表示出发城市、目的地城市和你初始拥有的汽油总量 每一步中,如果你在城市 i ,你可以选择任意一个城市 j ,满足 j != i 且 0 ,并移动到城市 …

category

3

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

困难 · 状态·转移·动态规划

bolt

答案摘要

我们设计一个函数 $dfs(i, k)$,表示从城市 出发,剩余汽油量为 时,到达目的地 的路径数。那么答案就是 $dfs(start, fuel)$。 函数 $dfs(i, k)$ 的计算过程如下:

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个 互不相同 的整数数组,其中 locations[i] 表示第 i 个城市的位置。同时给你 startfinish 和 fuel 分别表示出发城市、目的地城市和你初始拥有的汽油总量

每一步中,如果你在城市 i ,你可以选择任意一个城市 j ,满足  j != i 且 0 <= j < locations.length ,并移动到城市 j 。从城市 i 移动到 j 消耗的汽油量为 |locations[i] - locations[j]||x| 表示 x 的绝对值。

请注意, fuel 任何时刻都 不能 为负,且你 可以 经过任意城市超过一次(包括 start 和 finish )。

请你返回从 start 到 finish 所有可能路径的数目。

由于答案可能很大, 请将它对 10^9 + 7 取余后返回。

 

示例 1:

输入:locations = [2,3,6,8,4], start = 1, finish = 3, fuel = 5
输出:4
解释:以下为所有可能路径,每一条都用了 5 单位的汽油:
1 -> 3
1 -> 2 -> 3
1 -> 4 -> 3
1 -> 4 -> 2 -> 3

示例 2:

输入:locations = [4,3,1], start = 1, finish = 0, fuel = 6
输出:5
解释:以下为所有可能的路径:
1 -> 0,使用汽油量为 fuel = 1
1 -> 2 -> 0,使用汽油量为 fuel = 5
1 -> 2 -> 1 -> 0,使用汽油量为 fuel = 5
1 -> 0 -> 1 -> 0,使用汽油量为 fuel = 3
1 -> 0 -> 1 -> 0 -> 1 -> 0,使用汽油量为 fuel = 5

示例 3:

输入:locations = [5,2,1], start = 0, finish = 2, fuel = 3
输出:0
解释:没有办法只用 3 单位的汽油从 0 到达 2 。因为最短路径需要 4 单位的汽油。

 

提示:

  • 2 <= locations.length <= 100
  • 1 <= locations[i] <= 109
  • 所有 locations 中的整数 互不相同 。
  • 0 <= start, finish < locations.length
  • 1 <= fuel <= 200
lightbulb

解题思路

方法一:记忆化搜索

我们设计一个函数 dfs(i,k)dfs(i, k),表示从城市 ii 出发,剩余汽油量为 kk 时,到达目的地 finishfinish 的路径数。那么答案就是 dfs(start,fuel)dfs(start, fuel)

函数 dfs(i,k)dfs(i, k) 的计算过程如下:

  • 如果 k<locations[i]locations[finish]k \lt |locations[i] - locations[finish]|,那么返回 00
  • 如果 i=finishi = finish,那么答案路径数初始时为 11,否则为 00
  • 然后,我们遍历所有城市 jj,如果 jij \ne i,那么我们可以从城市 ii 移动到城市 jj,此时剩余汽油量为 klocations[i]locations[j]k - |locations[i] - locations[j]|,那么我们可以将答案路径数加上 dfs(j,klocations[i]locations[j])dfs(j, k - |locations[i] - locations[j]|)
  • 最后,我们返回答案路径数。

为了避免重复计算,我们可以使用记忆化搜索。

时间复杂度 O(n2×m)O(n^2 \times m),空间复杂度 O(n×m)O(n \times m)。其中 nnmm 分别是数组 locationslocationsfuelfuel 的大小。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Solution:
    def countRoutes(
        self, locations: List[int], start: int, finish: int, fuel: int
    ) -> int:
        @cache
        def dfs(i: int, k: int) -> int:
            if k < abs(locations[i] - locations[finish]):
                return 0
            ans = int(i == finish)
            for j, x in enumerate(locations):
                if j != i:
                    ans = (ans + dfs(j, k - abs(locations[i] - x))) % mod
            return ans

        mod = 10**9 + 7
        return dfs(start, fuel)
speed

复杂度分析

指标
时间and space complexity depend on the number of unique states, bounded by number of cities times fuel capacity. Memoization reduces exponential recursion to O(n * fuel) states, each potentially checking O(n) transitions.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Focus on memoizing (city, fuel) states rather than tracking exact paths.

  • question_mark

    Recognize revisiting cities is allowed and must be handled without double-counting errors.

  • question_mark

    Check edge cases where fuel is insufficient for even the direct move from start to finish.

warning

常见陷阱

外企场景
  • error

    Failing to memoize states, causing exponential timeouts.

  • error

    Subtracting fuel incorrectly or allowing negative fuel states.

  • error

    Ignoring that visiting the same city multiple times is valid and needed for some routes.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Compute routes with a maximum number of stops instead of fuel limit.

  • arrow_right_alt

    Count only routes that visit each city at most once while respecting fuel constraints.

  • arrow_right_alt

    Optimize for minimal total fuel to reach finish while counting only feasible paths.

help

常见问题

外企场景

统计所有可行路径题解:状态·转移·动态规划 | LeetCode #1575 困难