|
| 1 | +# 题目地址(1345. 跳跃游戏 IV) |
| 2 | + |
| 3 | +https://leetcode-cn.com/problems/jump-game-iv/ |
| 4 | + |
| 5 | +## 题目描述 |
| 6 | + |
| 7 | +``` |
| 8 | +给你一个整数数组 arr ,你一开始在数组的第一个元素处(下标为 0)。 |
| 9 | +
|
| 10 | +每一步,你可以从下标 i 跳到下标: |
| 11 | +
|
| 12 | +i + 1 满足:i + 1 < arr.length |
| 13 | +i - 1 满足:i - 1 >= 0 |
| 14 | +j 满足:arr[i] == arr[j] 且 i != j |
| 15 | +请你返回到达数组最后一个元素的下标处所需的 最少操作次数 。 |
| 16 | +
|
| 17 | +注意:任何时候你都不能跳到数组外面。 |
| 18 | +
|
| 19 | + |
| 20 | +
|
| 21 | +示例 1: |
| 22 | +
|
| 23 | +输入:arr = [100,-23,-23,404,100,23,23,23,3,404] |
| 24 | +输出:3 |
| 25 | +解释:那你需要跳跃 3 次,下标依次为 0 --> 4 --> 3 --> 9 。下标 9 为数组的最后一个元素的下标。 |
| 26 | +示例 2: |
| 27 | +
|
| 28 | +输入:arr = [7] |
| 29 | +输出:0 |
| 30 | +解释:一开始就在最后一个元素处,所以你不需要跳跃。 |
| 31 | +示例 3: |
| 32 | +
|
| 33 | +输入:arr = [7,6,9,6,9,6,9,7] |
| 34 | +输出:1 |
| 35 | +解释:你可以直接从下标 0 处跳到下标 7 处,也就是数组的最后一个元素处。 |
| 36 | +示例 4: |
| 37 | +
|
| 38 | +输入:arr = [6,1,9] |
| 39 | +输出:2 |
| 40 | +示例 5: |
| 41 | +
|
| 42 | +输入:arr = [11,22,7,7,7,7,7,7,7,22,13] |
| 43 | +输出:3 |
| 44 | + |
| 45 | +
|
| 46 | +提示: |
| 47 | +
|
| 48 | +1 <= arr.length <= 5 * 10^4 |
| 49 | +-10^8 <= arr[i] <= 10^8 |
| 50 | +
|
| 51 | +``` |
| 52 | + |
| 53 | +## 前置知识 |
| 54 | + |
| 55 | +- BFS |
| 56 | + |
| 57 | +## 思路 |
| 58 | + |
| 59 | +求最少的题目,考虑动态规划,贪心 和 BFS。 |
| 60 | + |
| 61 | +这道题没有想到贪心的做法,于是考虑到了动态规划。不过由于**arr[i] == arr[j] 且 i != j**也可以转移,因此这里涉及到了一个**连通性变更**的问题,代码会比较难写。 |
| 62 | + |
| 63 | +于是继续考虑 BFS。BFS 解题需要考虑三点: |
| 64 | + |
| 65 | +- 初始点。 这里是 0 |
| 66 | +- 终点。这里是 n - 1,其中 n 为数组长度。 |
| 67 | +- 节点状态转移。这里是题目列举的三种情况。前两个非常简单,最后一个只需要建立一个 hashtable,将相同值的索引合并到一个 list 即可。具体请看代码。 |
| 68 | + |
| 69 | +这里我直接使用 BFS 的模板提交了,结果超时了。用例卡在了 [7,7,7,7,7,7............] 无数个 7 上。 |
| 70 | + |
| 71 | +如果使用标准模板的 BFS,那么每一个 7 都会遍历到其他的所有 7,算法在这种情况下时间复杂度会退化到 $O(N^2)$。其实这里有一个上面讲的**连通性**的问题。如果 7 的 steps 求出来是 x,那么所有的 7 都是 x(不会比 7 大,也不会比 7 小),没有必要继续找了。因此一个剪枝就是遍历到 7 之后就将同值从 hashtable 中都清空。这个剪枝可将时间复杂度直接从 $N^2$ 降低到 $O(N)$。 |
| 72 | + |
| 73 | +## 代码 |
| 74 | + |
| 75 | +代码支持: Python3 |
| 76 | + |
| 77 | +```py |
| 78 | +class Solution: |
| 79 | + def minJumps(self, A: List[int]) -> int: |
| 80 | + dic = collections.defaultdict(list) |
| 81 | + n = len(A) |
| 82 | + |
| 83 | + for i, a in enumerate(A): |
| 84 | + dic[a].append(i) |
| 85 | + visited = set([0]) |
| 86 | + q = collections.deque([0]) |
| 87 | + steps = 0 |
| 88 | + |
| 89 | + while q: |
| 90 | + for _ in range(len(q)): |
| 91 | + i = q.popleft() |
| 92 | + visited.add(i) |
| 93 | + if i == n - 1: return steps |
| 94 | + for neibor in dic[A[i]] + [i - 1, i + 1]: |
| 95 | + if 0 <= neibor < n and neibor not in visited: |
| 96 | + q.append(neibor) |
| 97 | + # 剪枝 |
| 98 | + dic[A[i]] = [] |
| 99 | + steps += 1 |
| 100 | + return -1 |
| 101 | +``` |
| 102 | + |
| 103 | +**复杂度分析** |
| 104 | + |
| 105 | +- 时间复杂度:$O(N)$,其中 N 为数组长度。 |
| 106 | +- 空间复杂度:$O(N)$,其中 N 为数组长度。 |
| 107 | + |
| 108 | +更多题解可以访问我的 LeetCode 题解仓库:https://github.com/azl397985856/leetcode 。 目前已经 37K star 啦。 |
| 109 | + |
| 110 | +大家也可以关注我的公众号《力扣加加》获取更多更新鲜的 LeetCode 题解 |
| 111 | + |
| 112 | + |
0 commit comments