Medium
题目描述
给你一个非负整数数组 arr,你最初位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i + arr[i] 或者 i - arr[i]。
请你判断自己是否能够跳到对应元素值为 0 的 任一 下标处。
注意,不能跳出数组外。
示例 1:
输入:arr = [4,2,3,0,3,1,2], start = 5
输出:true
解释:
到达值为 0 的下标 3 有以下可能方案:
下标 5 -> 下标 4 -> 下标 1 -> 下标 3
下标 5 -> 下标 6 -> 下标 4 -> 下标 1 -> 下标 3
示例 2:
输入:arr = [4,2,3,0,3,1,2], start = 0
输出:true
解释:
到达值为 0 的下标 3 有以下可能方案:
下标 0 -> 下标 4 -> 下标 1 -> 下标 3
示例 3:
输入:arr = [3,0,2,1,2], start = 2
输出:false
解释:无法到达值为 0 的下标 1 处。
提示:
1 <= arr.length <= 5 * 10^40 <= arr[i] < arr.length0 <= start < arr.length
解题思路
这是一个典型的图遍历问题,可以用 BFS 或 DFS 来解决。
核心思路:
从起始位置 start 开始,我们可以向左跳(i - arr[i])或向右跳(i + arr[i])。每次跳跃后检查新位置是否有效(在数组范围内且未访问过),如果新位置的值为 0,则返回 true。
解法对比:
- BFS(推荐):使用队列进行层序遍历,能够找到最短路径,逻辑清晰
- DFS:使用递归或栈进行深度优先搜索,代码更简洁但可能栈溢出
BFS 实现步骤:
- 使用队列存储可达位置和访问数组避免重复访问
- 从起始位置开始,计算两个可能的跳跃位置
- 检查新位置是否在数组范围内且未被访问
- 如果新位置值为 0 则返回 true,否则加入队列继续搜索
- 队列为空时仍未找到则返回 false
时间复杂度为 O(n),空间复杂度为 O(n),其中 n 为数组长度。
代码实现
class Solution {
public:
bool canReach(vector<int>& arr, int start) {
int n = arr.size();
vector<bool> visited(n, false);
queue<int> q;
q.push(start);
visited[start] = true;
while (!q.empty()) {
int curr = q.front();
q.pop();
if (arr[curr] == 0) {
return true;
}
// 向右跳
int right = curr + arr[curr];
if (right < n && !visited[right]) {
visited[right] = true;
q.push(right);
}
// 向左跳
int left = curr - arr[curr];
if (left >= 0 && !visited[left]) {
visited[left] = true;
q.push(left);
}
}
return false;
}
};
class Solution:
def canReach(self, arr: List[int], start: int) -> bool:
n = len(arr)
visited = [False] * n
queue = deque([start])
visited[start] = True
while queue:
curr = queue.popleft()
if arr[curr] == 0:
return True
# 向右跳
right = curr + arr[curr]
if right < n and not visited[right]:
visited[right] = True
queue.append(right)
# 向左跳
left = curr - arr[curr]
if left >= 0 and not visited[left]:
visited[left] = True
queue.append(left)
return False
public class Solution {
public bool CanReach(int[] arr, int start) {
int n = arr.Length;
bool[] visited = new bool[n];
Queue<int> queue = new Queue<int>();
queue.Enqueue(start);
visited[start] = true;
while (queue.Count > 0) {
int curr = queue.Dequeue();
if (arr[curr] == 0) {
return true;
}
// 向右跳
int right = curr + arr[curr];
if (right < n && !visited[right]) {
visited[right] = true;
queue.Enqueue(right);
}
// 向左跳
int left = curr - arr[curr];
if (left >= 0 && !visited[left]) {
visited[left] = true;
queue.Enqueue(left);
}
}
return false;
}
}
var canReach = function(arr, start) {
const n = arr.length;
const visited = new Array(n).fill(false);
const queue = [start];
visited[start] = true;
while (queue.length > 0) {
const curr = queue.shift();
if (arr[curr]
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | 每个位置最多访问一次,n 为数组长度 |
| 空间复杂度 | O(n) | 需要 visited 数组和队列存储,最坏情况下队列大小为 n |
相关题目
. Jump Game II (Medium)
. Jump Game (Medium)
. Jump Game VII (Medium)
. Jump Game VIII (Medium)