[LeetCode] 683. K Empty Slots K個空槽


 

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

 

這道題給了我們這樣一個場景,說是花園里有N個空槽,可以放花,每天放一朵開着的花,而且一旦放了就會一直開下去。不是按順序放花,而是給了我們一個數組 flowers,其中 flowers[i] = x 表示第i天放的花會在位置x。其實題目這里有誤,數組是從0開始的,而天數和位置都是從1開始的,所以正確的應該是第 i+1 天放的花會在位置x。然后給了我們一個整數k,讓我們判斷是否正好有兩朵盛開的花中間有k個空槽,如果有,返回當前天數,否則返回-1。博主剛開始想的是先用暴力破解來做,用一個狀態數組,如果該位置有花為1,無花為0,然后每增加一朵花,就遍歷一下狀態數組,找有沒有連續k個0,結果TLE了。這說明,應該等所有花都放好了,再來找才行,但是這樣僅用0和1的狀態數組是不行的,我們得換個形式。

我們用一個 days 數組,其中 days[i] = t 表示在 i+1 位置上會在第t天放上花,那么如果 days 數組為 [1 3 2],就表示第一個位置會在第一天放上花,第二個位置在第三天放上花,第三個位置在第二天放上花。我們想,在之前的狀態數組中,0表示沒放花,1表示放了花,而 days 數組中的數字表示放花的天數,那么就是說數字大的就是花放的時間晚,那么在當前時間i,所有大於i的是不是也就是可以看作是沒放花呢,這樣問題就迎刃而解了,我們來找一個 k+2 大小的子數組,除了首尾兩個數字,中間的k個數字都要大於首尾兩個數字即可,那么首尾兩個數字中較大的數就是當前的天數。left 和 right 是這個大小為 k+2 的窗口,初始化時 left 為0,right 為 k+1,然后i從0開始遍歷,這里循環的條件時 right 小於n,當窗口的右邊界越界后,循環自然需要停止。如果當 days[i] 小於 days[left],或者 days[i] 小於等於 days[right] 的時候,有兩種情況,一種是i在[left, right]范圍內,說明窗口中有數字小於邊界數字,這不滿足我們之前限定的條件,至於days[i]為何可以等於 days[right],是因為當i遍歷到 right 到位置時,說明中間的數字都是大於左右邊界數的,此時我們要用左右邊界中較大的那個數字更新結果 res。不管i是否等於 right,只要進了這個if條件,說明當前窗口要么是不合題意,要么是遍歷完了,我們此時要重新給 left 和 right 賦值,其中 left 賦值為i,right 賦值為 k+1+i,還是大小為 k+2 的窗口,繼續檢測。最后我們看結果 res,如果還是 INT_MAX,說明無法找到,返回 -1 即可,參見代碼如下:

 

解法一:

class Solution {
public:
    int kEmptySlots(vector<int>& flowers, int k) {
        int res = INT_MAX, left = 0, right = k + 1, n = flowers.size();
        vector<int> days(n, 0);
        for (int i = 0; i < n; ++i) days[flowers[i] - 1] = i + 1;
        for (int i = 0; right < n; ++i) {
            if (days[i] < days[left] || days[i] <= days[right]) {
                if (i == right) res = min(res, max(days[left], days[right]));
                left = i; 
                right = k + 1 + i;
            }
        }
        return (res == INT_MAX) ? -1 : res;
    }
};

 

下面這種方法用到了 TreeSet 來做,利用其自動排序的特點,然后用 lower_bound 和 upper_bound 進行快速的二分查找。 題目中的 flowers[i] = x 表示第 i+1 天放的花會在位置x。所以我們遍歷 flowers 數組,其實就是按照時間順序進行的,我們取出當前需要放置的位置 cur,然后在集合 TreeSet 中查找第一個大於 cur 的數字,如果存在的話,說明兩者中間點位置都沒有放花,而如果中間正好有k個空位的話,那么當前天數就即為所求。這是當 cur 為左邊界的情況,同樣,我們可以把 cur 當右邊界來檢測,在集合 TreeSet 中查找第一個小於 cur 的數字,如果二者中間有k個空位,也返回當前天數。需要注意的是,C++ 和 Java 中的 upper_bound 和 higher 是相同作用的,但是 lower_bound 和 lower 卻不太一樣。C++ 中的 lower_bound 找的是第一個不小於目標值的數字,所以可能會返回和目標值相同或者大於目標值的數字。只要這個數字不是第一個數字,然后我們往前退一位,就是要求的第一個小於目標值的數字,這相當於 Java 中的 lower 函數,參見代碼如下:

 

解法二:

class Solution {
public:
    int kEmptySlots(vector<int>& flowers, int k) {
        set<int> s;
        for (int i = 0; i < flowers.size(); ++i) {
            int cur = flowers[i];
            auto it = s.upper_bound(cur);
            if (it != s.end() && *it - cur == k + 1) {
                return i + 1;
            }
            it = s.lower_bound(cur);
            if (it != s.begin() && cur - *(--it) == k + 1) {
                return i + 1;
            }
            s.insert(cur);
        }
        return -1;
    }
};

 

討論:這道題有一個很好的 follow up,就是改為最后的有k盆連續開花的是哪一天,就是k個連續不空的槽,博主沒有想出特別好的解法,只能采用暴力搜索的解法。比如就像解法一,求出了 days 數組后。我們可以遍歷每個長度為k的子數組,然后找出該子數組中最大的數字,然后找出所有的這些最大數字中的最小的一個,就是所求。或者,我們可以使用類似於合並區間的思想,遍歷 flowers 數組,每遍歷一個數字,如果跟現有的區間連續,就加入當前區間,直到出現某個區間的長度大於等於k了,則當前天數即為所求。如果各位看官大神們有更好的解法,一定要留言告知博主哈~

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/683

 

參考資料:

https://leetcode.com/problems/k-empty-slots/

https://leetcode.com/problems/k-empty-slots/discuss/107931/JavaC%2B%2B-Simple-O(n)-solution

https://leetcode.com/problems/k-empty-slots/discuss/107960/C%2B%2B-ordered-set-Easy-solution

https://leetcode.com/problems/k-empty-slots/discuss/107948/Iterate-over-time-vs.-iterate-over-position

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM