给你一个下标从 0 开始的二进制字符串 s
和两个整数 minJump
和 maxJump
。一开始,你在下标 0
处,且该位置的值一定为 '0'
。当同时满足如下条件时,你可以从下标 i
移动到下标 j
处:
i + minJump <= j <= min(i + maxJump, s.length - 1)
且s[j] == '0'
.
如果你可以到达 s
的下标 s.length - 1
处,请你返回 true
,否则返回 false
。
示例 1:
输入:s = "011010", minJump = 2, maxJump = 3 输出:true 解释: 第一步,从下标 0 移动到下标 3 。 第二步,从下标 3 移动到下标 5 。
示例 2:
输入:s = "01101110", minJump = 2, maxJump = 3 输出:false
提示:
2 <= s.length <= 105
s[i]
要么是'0'
,要么是'1'
s[0] == '0'
1 <= minJump <= maxJump < s.length
“动态规划 + 前缀和”实现。
class Solution:
def canReach(self, s: str, minJump: int, maxJump: int) -> bool:
n = len(s)
dp = [False] * n
dp[0] = True
pre_sum = [0] * (n + 1)
pre_sum[1] = 1
for i in range(1, n):
if s[i] == '0':
l = max(0, i - maxJump)
r = i - minJump
if r >= l and pre_sum[r + 1] - pre_sum[l] > 0:
dp[i] = True
pre_sum[i + 1] = pre_sum[i] + dp[i]
return dp[n - 1]
class Solution {
public boolean canReach(String s, int minJump, int maxJump) {
int n = s.length();
boolean[] dp = new boolean[n];
dp[0] = true;
int[] preSum = new int[n + 1];
preSum[1] = 1;
for (int i = 1; i < n; ++i) {
if (s.charAt(i) == '0') {
int l = Math.max(0, i - maxJump);
int r = i - minJump;
if (r >= l && preSum[r + 1] - preSum[l] > 0) {
dp[i] = true;
}
}
preSum[i + 1] = preSum[i] + (dp[i] ? 1 : 0);
}
return dp[n - 1];
}
}
/**
* @param {string} s
* @param {number} minJump
* @param {number} maxJump
* @return {boolean}
*/
var canReach = function (s, minJump, maxJump) {
let n = s.length;
let dp = new Array(n).fill(0);
let sum = new Array(n + 1).fill(0);
dp[0] = 1;
sum[1] = 1;
for (let i = 1; i < n; i++) {
if (s.charAt(i) == '0') {
let left = Math.max(0, i - maxJump);
let right = i - minJump;
if (left <= right && sum[right + 1] - sum[left] > 0) {
dp[i] = 1;
}
}
sum[i + 1] = sum[i] + dp[i];
}
return dp.pop();
};