leetcode
leetcode 3001 ~ 3050
环形闯关游戏

环形闯关游戏

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 441 ms, 内存: 32.2 MB


/*
 * 思路:
 * 同样是寻找最小的初始积分来挑战所有关卡。
 * 使用Java Stream来处理逻辑,尽量简化代码。
 */

import java.util.stream.IntStream;

public class SolutionStream {
    public int minInitialScore(int[] challenge) {
        int N = challenge.length;
        int minScore = IntStream.of(challenge).reduce(0, (a, b) -> a | b);

        return IntStream.range(0, N).anyMatch(i -> canCompleteAll(challenge, minScore, i)) ? minScore : minScore;
    }

    private boolean canCompleteAll(int[] challenge, int score, int start) {
        int N = challenge.length;
        boolean[] opened = new boolean[N];
        int completed = 0;
        int[] queue = new int[N];
        int front = 0, rear = 0;

        queue[rear++] = start;
        opened[start] = true;

        while (front != rear) {
            int curr = queue[front++];
            front %= N;

            if (score >= challenge[curr]) {
                score |= challenge[curr];
                completed++;

                int left = (curr + N - 1) % N;
                int right = (curr + 1) % N;

                if (!opened[left]) {
                    queue[rear++] = left;
                    rear %= N;
                    opened[left] = true;
                }
                if (!opened[right]) {
                    queue[rear++] = right;
                    rear %= N;
                    opened[right] = true;
                }
            }
        }

        return completed == N;
    }
}

解释

方法:

此题解的核心思想是利用二分搜索和双指针技术来寻找最小的初始积分,以挑战所有关卡。首先,找到挑战值最大的关卡,并以此关卡为基点重构环形数组为线性数组,以简化问题。然后,使用二分搜索从可能的最低积分开始,使用双指针检测该积分是否足以开始并完成游戏。在二分搜索的每一步,会尝试将挑战分和数组两侧的积分合并,检查能否覆盖整个数组。这种方法有效地将环形结构转化为线性结构,从而简化了逻辑判断。

时间复杂度:

O(n log(max_value))

空间复杂度:

O(n)

代码细节讲解

🦆
为什么需要将环形数组转换为线性数组来处理这个问题?这种转换对问题解决有什么具体帮助?
将环形数组转换为线性数组是为了简化问题的处理。在环形结构中,数组的末尾与开头相连,这使得处理边界条件和遍历时的逻辑变得复杂。通过将环形数组以最大值所在的位置为断点重构为线性数组,可以将问题从一个循环处理问题转变为一个更容易管理的线性处理问题。这种转换使得数组的遍历和检查变得直接明了,减少了复杂的边界判断,从而提高了代码的可读性和易于管理。
🦆
在二分搜索过程中,如何确定二分的初始上界和下界?特别是初始上界是如何计算得出的?
在题解中,二分搜索的初始下界设为0,上界设为最大关卡挑战值的二进制长度左移1位的结果。具体来说,上界的计算方法是将最大挑战值的二进制表示长度减一后,结果为1的位数左移一位。这样做是基于对问题的理解:一个合理的起始上界应该足够大,能够覆盖最大的单一挑战,并且还应有余地以确保可以通过其他较小的挑战。这种设置上界的方法是为了确保在二分搜索开始时,有一个足够宽的搜索范围来逐步缩小至最优解。
🦆
双指针策略在每次二分搜索中如何具体实现?是如何通过双指针检测判断当前积分是否足够覆盖所有关卡的?
双指针策略在本题中是通过设置一个左指针和一个右指针来实现的,这两个指针分别从当前考察的关卡的左右两侧开始移动。在每次二分搜索尝试的过程中,会从挑战数组中的某一点开始,用当前的积分尝试向左右两边扩展。如果当前积分足够覆盖左侧或右侧的下一个关卡,相应的指针就会移动一位,并将该关卡的挑战值合并入当前积分。这个过程会一直持续,直到指针超出数组边界或无法继续向某方向扩展(因为挑战值大于当前积分)。如果在某次尝试中,左右指针能够覆盖整个数组,那么说明当前积分足够通过所有关卡。

相关问题