跳跃游戏 IV
难度:
标签:
题目描述
代码结果
运行时间: 122 ms, 内存: 33.1 MB
/*
* 思路:同样是使用广度优先搜索(BFS),但这次利用Java Stream API进行部分简化。
* 首先用流来构建值到索引的映射。
* 然后使用一个队列进行BFS搜索,记录访问过的节点并计算步数。
*/
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class Solution {
public int minJumps(int[] arr) {
if (arr.length <= 1) return 0;
Map<Integer, List<Integer>> valueToIndices = IntStream.range(0, arr.length)
.boxed()
.collect(Collectors.groupingBy(i -> arr[i]));
Queue<Integer> queue = new LinkedList<>();
queue.offer(0);
boolean[] visited = new boolean[arr.length];
visited[0] = true;
int steps = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
int currentIndex = queue.poll();
if (currentIndex == arr.length - 1) return steps;
List<Integer> nextIndices = new ArrayList<>(valueToIndices.getOrDefault(arr[currentIndex], new ArrayList<>()));
if (currentIndex + 1 < arr.length) nextIndices.add(currentIndex + 1);
if (currentIndex - 1 >= 0) nextIndices.add(currentIndex - 1);
for (int nextIndex : nextIndices) {
if (nextIndex >= 0 && nextIndex < arr.length && !visited[nextIndex]) {
queue.offer(nextIndex);
visited[nextIndex] = true;
}
}
nextIndices.clear();
}
steps++;
}
return -1;
}
}
解释
方法:
这个问题可以通过使用宽度优先搜索(BFS)来解决。首先,我们使用一个字典 `d` 来存储数组中每个元素的所有下标。接着,我们从数组的第一个元素开始,使用一个队列 `cur` 来保存当前可以访问的下标。每次从队列中取出一个下标,我们都会尝试向左跳(i-1)、向右跳(i+1),以及跳到所有值相同的位置(通过查找字典 `d`)。使用一个数组 `dp` 来记录到达每个下标的最少操作次数,初始时,除了第一个元素设为0以外,其余都设为-1表示未访问。此外,我们使用一个集合 `visited_num` 来记录已经使用过的数字,避免重复访问导致的无效操作。算法的核心在于逐层扩展,直到到达数组的最后一个元素。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在BFS中使用数组dp来记录每个下标的最少操作次数,而不是直接使用队列中的层数来代表步数?
▷🦆
在题解中,visited_num集合是用来记录已经访问过的数字,这样做的目的是什么?是否存在某些情况下重复访问相同的数字值是必要的?
▷🦆
题解中提到,当找到目标位置n-1时就可以立即结束搜索。这种提前终止搜索的方法是否可能导致没有探索到其他可能的最短路径?
▷🦆
在处理跳到所有值相同的位置时,为什么选择在访问过数字后再添加到visited_num集合,而不是在取出数字时就添加?
▷