Formatted question description: https://leetcode.ca/all/683.html

683. K Empty Slots

Level

Hard

Description

You have N bulbs in a row numbered from 1 to N. Initially, all the bulbs are turned off. We turn on exactly one bulb everyday until all bulbs are on after N days.

You are given an array bulbs of length N where bulbs[i] = x means that on the (i+1)th day, we will turn on the bulb at position x where i is 0-indexed and x is 1-indexed.

Given an integer K, find out the minimum day number such that there exists two turned on bulbs that have exactly K bulbs between them that are all turned off.

If there isn’t such day, return -1.

Example 1:

Input:

bulbs: [1,3,2]

K: 1

Output: 2

Explanation:

On the first day: bulbs[0] = 1, first bulb is turned on: [1,0,0]

On the second day: bulbs[1] = 3, third bulb is turned on: [1,0,1]

On the third day: bulbs[2] = 2, second bulb is turned on: [1,1,1]

We return 2 because on the second day, there were two on bulbs with one off bulb between them.

Example 2:

Input:

bulbs: [1,2,3]

K: 1

Output: -1

Note:

  1. 1 <= N <= 20000
  2. 1 <= bulbs[i] <= N
  3. bulbs is a permutation of numbers from 1 to N.
  4. 0 <= K <= 20000

Solution

Create a class Interval that represents continuous intervals of turned off bulbs. Each object of Interval has data fields start and end that represents the start position and the end position. The intervals are compared according to start in ascending order and then according to end in ascending order.

Maintain a map that stores each day and the index of the bulb that is turned on. Also maintain a tree set to store the intervals, where the intervals are sorted in ascending order. Initially, the tree set contains a single interval [1, N]. On the first day, since only one bulb is turned on, there do not exist two bulbs that are turned on, so simply update the tree set after the first bulb is turned on. After the first day, the tree set man contain one interval or two intervals. From the second day, each day obtain the maximum interval that has start less than or equal to the current bulb’s index, which contains the current bulb’s index. It is guaranteed that such an interval exists, since all turned off bulbs are in the intervals.

If the current bulb’s index equals the start of the interval or the end of the interval, then if K is 0 and the bulb is not at any end of the row (that is, the bulb is not at index 1 or index N), return the current day. Otherwise, remove the previous interval and add one new interval to the tree set.

If the current bulb’s index is in the middle of the interval (not at the start or the end of the interval), then the current interval will be split after the current bulb is turned on. Check the two intervals. If one interval has length K and its start position is not 1 and its end position is not N, then return the current day. Otherwise, remove the previous interval and add two new intervals to the tree set.

If an interval of length K that is not at the start or the end of the row is found, return -1.

class Solution {
    public int kEmptySlots(int[] bulbs, int K) {
        Map<Integer, Integer> dayIndexMap = new HashMap<Integer, Integer>();
        int length = bulbs.length;
        for (int i = 0; i < length; i++)
            dayIndexMap.put(i + 1, bulbs[i]);
        TreeSet<Interval> set = new TreeSet<Interval>();
        int bulb1 = bulbs[0];
        if (bulb1 == 1)
            set.add(new Interval(2, length));
        else if (bulb1 == length)
            set.add(new Interval(1, length - 1));
        else {
            set.add(new Interval(1, bulb1 - 1));
            set.add(new Interval(bulb1 + 1, length));
        }
        for (int i = 1; i < length; i++) {
            int day = i + 1;
            int bulb = bulbs[i];
            Interval curr = set.floor(new Interval(bulb, length));
            set.remove(curr);
            if (curr.start == bulb) {
                if (K == 0 && bulb > 1)
                    return day;
                else if (curr.end < length && curr.end - bulb == K)
                    return day;
                else
                    set.add(new Interval(bulb + 1, curr.end));
            } else if (curr.end == bulb) {
                if (K == 0 && bulb < length)
                    return day;
                else if (curr.start > 1 && bulb - curr.start == K)
                    return day;
                else
                    set.add(new Interval(curr.start, bulb - 1));
            } else {
                if (curr.start > 1 && bulb - curr.start == K || curr.end < length && curr.end - bulb == K)
                    return day;
                else {
                    set.add(new Interval(curr.start, bulb - 1));
                    set.add(new Interval(bulb + 1, curr.end));
                }
            }
        }
        return -1;
    }
}

class Interval implements Comparable<Interval> {
    int start;
    int end;

    public Interval(int start, int end) {
        this.start = start;
        this.end = end;
    }

    public int compareTo(Interval interval2) {
        if (this.start != interval2.start)
            return this.start - interval2.start;
        else
            return this.end - interval2.end;
    }

    public boolean equals(Object obj) {
        if (obj instanceof Interval) {
            Interval interval2 = (Interval) obj;
            return this.start == interval2.start && this.end == interval2.end;
        } else
            return false;
    }
}

All Problems

All Solutions