Leetcode每日一题 —— 1871. 跳跃游戏 VII

Leetcode每日一题 —— 1871. 跳跃游戏 VII
Leetcode每日一题 —— 1871. 跳跃游戏 VII
力扣 LeetCode

1871. 跳跃游戏 VII - 力扣(LeetCode)

1871. 跳跃游戏 VII - 给你一个下标从 0 开始的二进制字符串 s 和两个整数 minJump 和 maxJump 。一开始,你在下标 0 处,且该位置的值一定为 '0' 。当同时满足如下条件时,你可以从下标 i 移动到下标 j 处: * i + minJump <= j <= min(i + maxJump, s.length - 1) 且 * s[j] == '0'. 如果你可以到达 s 的下标 s.length -...

思路
首先题目明显的无后效性,可以用动态规划作答。
容易想到遍历一遍,从[minJump..maxJump]进行递推,但是看数据量 1 <= minJump <= maxJump < s.length <= 10^5 大概率会超时。线段树似乎可以,但是太重了。
逆向思考下,如果能够到达 x 点,那么在 [x-maxJump..x-minJump] 至少有一个点可以到达。这点借助前缀和可以在O(1)的复杂度内解决,那动态规划的方程式就由O(n^2)降到了O(n)

代码

class Solution {
    public boolean canReach(String s, int minJump, int maxJump) {
        int n = s.length();
        // 是否可以跳到坐标
        boolean[] dp = new boolean[n];
        dp[0] = true;
        // 到当前坐标为止能够到达的坐标数量
        int[] prefix = new int[n];
        // 本来prefix[0]应该设为1,但是这样需要把[0..minJump)都设为1,所以在不影响计算的情况下此处保持0
        // prefix[0]= 1;
        // 初始化边界,[minJump..maxJump]只要为0均可到达
        for (int i = minJump; i <= maxJump; i++) {
            prefix[i] = prefix[i - 1];
            if (s.charAt(i) == '0') {
                dp[i] = true;
                prefix[i] += 1;
            }
        }
        // 只要前面 [i-maxJump..i-minJump] 范围内有点能够到达此处就能到达
        for (int i = maxJump + 1; i < n; i++) {
            prefix[i] = prefix[i - 1];
            if (s.charAt(i) == '0' && prefix[i - minJump] - prefix[i - maxJump - 1] > 0) {
                dp[i] = true;
                prefix[i] += 1;
            }
        }
        return dp[n - 1];
    }
}

1 个帖子 - 1 位参与者

阅读完整话题

来源: LinuxDo 最新话题查看原文