Woodyiiiiiii / LeetCode

My private record of Leetcode solution

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Leetcode 2612. Minimum Reverse Operations

Woodyiiiiiii opened this issue · comments

看完题目,首先想到的是在数组中使用BFS。

观察规律,结合k,可以发现扩散范围跟奇偶有关。接着就很容易写出BFS题解。但发现TLE了,说明最坏情况下时间复杂度是O(nk)。然后我就不知道如何优化。

赛后,这个卡点的解决方法是利用平衡树来取数,可以使时间复杂度缩减为O(n+nlgn)。提前存好奇偶索引,两个TreeSet,然后利用**ceilling(E e)**方法(该方法取大于等于e参数的最小值),如此可以优化取数算法。TreeSet内置就是个优化的链表+红黑树的结构。这种写法算是取数的一种黑科技了。

同时要注意界定取数时的最小值和最大值。如果没超出时间范围还好说,如果超出了,就需要从0或n-1开始计算k大小的范围内的索引变化了。这也算是个小卡点。

class Solution {
    public int[] minReverseOperations(int n, int p, int[] banned, int k) {
        int[] res = new int[n];
        boolean[] visited = new boolean[n];
        for (int j : banned) {
            res[j] = -1;
            visited[j] = true;
        }
        visited[p] = true;

        TreeSet<Integer> even = new TreeSet<>(), odd = new TreeSet<>();
        for (int i = 0; i < n; ++i) {
            if (visited[i]) continue;
            if (i % 2 == 0) even.add(i);
            else odd.add(i);
        }

        Queue<Integer> q = new ArrayDeque<>();
        q.add(p);
        int steps = 1;
        TreeSet<Integer> set = new TreeSet<>();
        int min, max, mCurrent;
        while (!q.isEmpty()) {
            int sz = q.size();
            while (sz-- > 0) {
                int cur = q.poll();
                if (k % 2 == 0) {
                    if (cur + 1 < n) {
                        set = (cur + 1) % 2 == 0 ? even : odd;
                    } else if (cur - 1 >= 0) {
                        set = (cur - 1) % 2 == 0 ? even : odd;
                    }
                } else {
                    set = cur % 2 == 0 ? even : odd;
                }

                // calculate min index
                if (cur < k - 1) {
                    min = (k - 1) - cur;
                }else {
                    min = cur - k + 1;
                }

                // calculate max index
                if (cur + k - 1 >= n) {
                    max = (n - k) + (n - cur - 1);
                }else {
                    max = cur + k - 1;
                }

                Integer mid = set.ceiling(min);
                while (mid != null && mid <= max) {
                    if (visited[mid]) {
                        set.remove(mid);
                        min += 2;
                        mid = set.ceiling(min);
                        continue;
                    }
                    visited[mid] = true;
                    q.add(mid);
                    res[mid] = steps;
                    set.remove(mid);
                    min += 2;
                    mid = set.ceiling(min);
                }
            }
            ++steps;
        }
        for (int i = 0; i < n; ++i) {
            if (res[i] == 0 && i != p) res[i] = -1;
        }
        return res;
    }
}

还有个并查集的写法,这里我不写了XD,可以看参考资料。

类似题目: