You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

155 lines
3.8 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2022_05_3_week;
import java.util.Arrays;
// 来自学员问题
// 为了给刷题的同学一些奖励,力扣团队引入了一个弹簧游戏机
// 游戏机由 N 个特殊弹簧排成一排,编号为 0 到 N-1
// 初始有一个小球在编号 0 的弹簧处。若小球在编号为 i 的弹簧处
// 通过按动弹簧可以选择把小球向右弹射 jump[i] 的距离,或者向左弹射到任意左侧弹簧的位置
// 也就是说,在编号为 i 弹簧处按动弹簧,
// 小球可以弹向 0 到 i-1 中任意弹簧或者 i+jump[i] 的弹簧(若 i+jump[i]>=N ,则表示小球弹出了机器)
// 小球位于编号 0 处的弹簧时不能再向左弹。
// 为了获得奖励,你需要将小球弹出机器。
// 请求出最少需要按动多少次弹簧,可以将小球从编号 0 弹簧弹出整个机器,即向右越过编号 N-1 的弹簧。
// 测试链接 : https://leetcode-cn.com/problems/zui-xiao-tiao-yue-ci-shu/
public class Code04_MinJumpUsePre {
// 宽度优先遍历
// N*logN
public int minJump(int[] jump) {
int n = jump.length;
int[] queue = new int[n];
int l = 0;
int r = 0;
queue[r++] = 0;
IndexTree it = new IndexTree(n);
// 1...n初始化的时候 每个位置填上1
for (int i = 1; i < n; i++) {
it.add(i, 1);
}
int step = 0;
while (l != r) { // 队列里面还有东西
// tmp记录了当前层的终止位置
int tmp = r;
// 当前层的所有节点,都去遍历!
for (; l < tmp; l++) {
int cur = queue[l];
int forward = cur + jump[cur];
if (forward >= n) {
return step + 1;
}
if (it.value(forward) != 0) {
queue[r++] = forward;
it.add(forward, -1);
}
// cur
// 1....cur-1 cur
while (it.sum(cur - 1) != 0) {
int find = find(it, cur - 1);
it.add(find, -1);
queue[r++] = find;
}
}
step++;
}
return -1;
}
public static int find(IndexTree it, int right) {
int left = 0;
int mid = 0;
int find = 0;
while (left <= right) {
mid = (left + right) / 2;
if (it.sum(mid) > 0) {
find = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return find;
}
public static class IndexTree {
private int[] tree;
private int N;
public IndexTree(int size) {
N = size;
tree = new int[N + 1];
}
public int value(int index) {
if (index == 0) {
return sum(0);
} else {
return sum(index) - sum(index - 1);
}
}
public int sum(int i) {
int index = i + 1;
int ret = 0;
while (index > 0) {
ret += tree[index];
index -= index & -index;
}
return ret;
}
public void add(int i, int d) {
int index = i + 1;
while (index <= N) {
tree[index] += d;
index += index & -index;
}
}
}
// 感谢黄汀同学
// 弄出了时间复杂度O(N)的过程
// 和大厂刷题班第10节jump game类似
public int minJump2(int[] jump) {
int N = jump.length;
int ans = N;
int next = jump[0];
if (next >= N) {
return 1;
}
if (next + jump[next] >= N) {
return 2;
}
// dp[i] : 来到i位置最少跳几步
int[] dp = new int[N + 1];
Arrays.fill(dp, N);
// dis[i] : <= i步的情况下最远能跳到哪
int[] dis = new int[N];
// 如果从0开始向前跳<=1步的情况下最远当然能到next
dis[1] = next;
// 如果从0开始向前跳<=2步的情况下最远可能比next + jump[next]要远,
// 这里先设置,以后可能更新
dis[2] = next + jump[next];
dp[next + jump[next]] = 2;
int step = 1;
for (int i = 1; i < N; i++) {
if (i > dis[step]) {
step++;
}
dp[i] = Math.min(dp[i], step + 1);
next = i + jump[i];
if (next >= N) {
ans = Math.min(ans, dp[i] + 1);
} else if (dp[next] > dp[i] + 1) {
dp[next] = dp[i] + 1;
dis[dp[next]] = Math.max(dis[dp[next]], next);
}
}
return ans;
}
}