欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > [LeetCode 1871] 跳跃游戏 7(Ⅶ)

[LeetCode 1871] 跳跃游戏 7(Ⅶ)

2025/5/18 19:47:40 来源:https://blog.csdn.net/qq_45371462/article/details/147257344  浏览:    关键词:[LeetCode 1871] 跳跃游戏 7(Ⅶ)

题面:

在这里插入图片描述

数据范围:

2 ≤ s . l e n g t h ≤ 1 0 5 2 \le s.length \le 10^5 2s.length105
s [ i ] s[i] s[i] 要么是 ′ 0 ′ '0' 0 ,要么是 ′ 1 ′ '1' 1
s [ 0 ] = = 0 s[0] == 0 s[0]==0
1 ≤ m i n J u m p ≤ m a x J u m p < s . l e n g t h 1 \le minJump \le maxJump < s.length 1minJumpmaxJump<s.length

思路 & Code

重点: s [ i ] = = 0 s[i]==0 s[i]==0 时,才能继续跳,也才能被跳到。
So,自然会想到存储所有能够跳到的 0 0 0 点,而当前 0 0 0 点必然是从存储的 0 0 0 点跳过来的。容易想到可以暴力状态转移

用一数组 d p dp dp 存储下标状态:

  1. d p [ i n d e x ] = = 0 dp[index]==0 dp[index]==0,说明 i n d e x index index 位置没有被跳到
  2. d p [ i n d e x ] = = 1 dp[index]==1 dp[index]==1 i n d e x index index 可以被跳到

那么,对于当前点 i n d e x index index 都得判断 [ m i n ( i − m a x J u m p ) , 0 ) , i − m i n J u m p ] [min(i-maxJump), 0), i-minJump] [min(imaxJump),0),iminJump] 区间内的所有可跳点,这样太暴力了, O ( n k ) O(nk) O(nk)。必须考虑优化。

差分维护

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

维护个前缀和,每次到 s [ i ] = = ′ 0 ′ s[i]=='0' s[i]==0(可跳点)时,判断区间 [ m i n ( i − m a x J u m p ) , 0 ) , i − m i n J u m p ] [min(i-maxJump), 0), i-minJump] [min(imaxJump),0),iminJump]是否存在可跳点 0 0 0,即 p r e [ i − m i n J u m p ] − p r e [ i − m a x J u m p − 1 ] pre[i-minJump] - pre[i-maxJump-1] pre[iminJump]pre[imaxJump1]是否大于零。(当然了,区间得注意下)

Code:

bool canReach(string s, int minJump, int maxJump) {int n = s.size();vector<int> dp(n, 0), pre(n, 0);dp[0] = 1;for(int i = 0; i < minJump; ++i) pre[i] = 1;for(int i = minJump; i < n; ++i) {int l = i - maxJump, r = i - minJump;// 差分判断可跳区间内是否存在 0 点if(s[i] == '0' && pre[r] - (l >= 1 ? pre[l - 1] : 0) > 0) dp[i]=1;pre[i] = pre[i-1] + dp[i];}return dp[n-1];/* 当然了,不用dp数组维护也可以写成:for(int i = minJump; i < n; ++i) {int l = i - maxJump, r = i - minJump;if(s[i] == '0' && pre[r] - (l >= 1 ? pre[l - 1] : 0) > 0) {if(i == n-1) return true;pre[i] = pre[i-1]+1;} else pre[i] = pre[i-1];}return false;*/
}

当然了,由于可跳区间其实就是一个滑动窗口,直接拿个临时变量存储可跳点个数就行,但得存个状态哈

Code:

bool canReach(string s, int minJump, int maxJump) {int n = s.size(), cnt = 1;vector<bool> dp(n, false);dp[0] = true;for(int i = minJump; i < n; ++ i) {if(s[i] == '0' && cnt) dp[i] = true;// 可跳区间要右移啦(其实就是动态维护滑动窗口的思想啦)// 如果左端点是可跳的,cnt--;如果要加入的点(右端点)是可跳的,cnt++if(i - maxJump >= 0 && dp[i - maxJump]) --cnt;if(i - minJump + 1 < n && dp[i - minJump + 1]) ++ cnt;}return dp[n-1];
}

动态维护滑动窗口(可跳区间)

上面都提到滑动窗口了,那直接拿个队列去维护滑动窗口也很简单啦。时间复杂度和空间复杂度都是 O ( n ) O(n) O(n)

Code:

bool canReach(string s, int minJump, int maxJump) {int n = s.size();if(s[n-1] == '1') return false;queue<int> q;q.push(0);for(int i = minJump; i < n; ++i) {if(s[i] == '1') continue;while(!q.empty() && q.front() < i - maxJump) q.pop();if(!q.empty() && q.front() <= i - minJump) {if(i == n-1) return true;q.push(i);}}return false;
}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词