實作餐廳訂位報號系統 Seat Reservation Manager Leetcode #1845

實作餐廳訂位報號系統 Seat Reservation Manager Leetcode #1845

更新於 發佈於 閱讀時間約 8 分鐘
raw-image

這題的題目在這裡:

題目敘述

題目會定義一組類別和介面,要求我們實做餐廳訂位報號系統。

SeatManager(int n) : 初始化餐廳最多有n個座位,n 最少是1

int reserve() : 要求返回最小的可讓客人入座的空座位編號。

void unreserve(int seatNumber) : 取消訂位,這個座位歸還給訂位系統。


測試範例

Example 1:

Input
["SeatManager", "reserve", "reserve", "unreserve", "reserve", "reserve", "reserve", "reserve", "unreserve"]
[[5], [], [], [2], [], [], [], [], [5]]
Output
[null, 1, 2, null, 2, 3, 4, 5, null]

Explanation
SeatManager seatManager = new SeatManager(5); // Initializes a SeatManager with 5 seats.
seatManager.reserve(); // All seats are available, so return the lowest numbered seat, which is 1.
seatManager.reserve(); // The available seats are [2,3,4,5], so return the lowest of them, which is 2.
seatManager.unreserve(2); // Unreserve seat 2, so now the available seats are [2,3,4,5].
seatManager.reserve(); // The available seats are [2,3,4,5], so return the lowest of them, which is 2.
seatManager.reserve(); // The available seats are [3,4,5], so return the lowest of them, which is 3.
seatManager.reserve(); // The available seats are [4,5], so return the lowest of them, which is 4.
seatManager.reserve(); // The only available seat is seat 5, so return 5.
seatManager.unreserve(5); // Unreserve seat 5, so now the available seats are [5].

約束條件

Constraints:

  • 1 <= n <= 105
  • 1 <= seatNumber <= n
  • For each call to reserve, it is guaranteed that there will be at least one unreserved seat.
  • For each call to unreserve, it is guaranteed that seatNumber will be reserved.
  • At most 10^5 calls in total will be made to reserve and unreserve.

演算法

題目已經給定座位號碼都是1~n的整數。

而且,剛好要求返回的帶位號碼是要求從當下最小的空位開始帶位。

很直覺的,可以想到用min Heap 最小堆積 搭配 當前最後一筆帶位號碼last_seat_num來實作整個餐廳訂位系統。


報空位帶位時,假如min Heap非空,代表有之前退還回來的空位,則從min Heap取出最小的空位號碼。

假如min Heap為空,代表沒有之前退還回來的空位。直接從1,2,3...的順序,從小到大回報空位即可,並且,把空位記錄在last_seat_num。


取消訂位時,假如取消的座位和last_seat_num相同,代表是取消剛剛近來的那筆最新的定位,這時侯,只要在last_seat_num減一,做取消訂位即可。

假如取消的座位和last_seat_num不同,代表是取消的很久以前的訂位,這時候就把取消的座位號碼推入min Heap 被退回空位的池子裡(本身用最小堆積來實作,保證之後取到的都是從小的號碼開始取)。


程式碼

class SeatManager:

 def __init__(self, n: int):

  # Build a minheap
  self.min_heap = []
  self.last_seat_num = 0

 def reserve(self) -> int:
  # pop out smallest number
  if self.min_heap:
   cur = heapq.heappop(self.min_heap)
   return cur
  
  else:
   self.last_seat_num += 1
   return self.last_seat_num
  

 def unreserve(self, seatNumber: int) -> None:
  if self.last_seat_num == seatNumber:
   self.last_seat_num -= 1
   
  else:
   # push unreserved number back to minheap
   heapq.heappush(self.min_heap, seatNumber)
  return


# Your SeatManager object will be instantiated and called as such:
# obj = SeatManager(n)
# param_1 = obj.reserve()
# obj.unreserve(seatNumber)​

複雜度分析

時間複雜度:

init(): O(1)

reserve(): O( log n ) min heap 取出頂端的最小值,並且調整min heap。

unreseve(): O( log n ) min heap 推入被退回的空位,並且調整min heap。

空間複雜度: O(n)
當全部訂位訂滿之後,從一號開始連續退回空位時,min heap所佔用空間有可能到達最大座位號碼O(n)


關鍵知識點

從餐廳帶位總是從最小號碼開始帶位,聯想到使用min heap最小堆積來實作


Reference:

[1] Seat Reservation Manager - LeetCode

avatar-img
小松鼠的演算法樂園
95會員
425內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言
avatar-img
留言分享你的想法!
題目會給們一個陣列,還有一個k值。 好陣列定義是: 有包含nums[k]的子陣列。 分數定義是: min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1) 其中, i, j 分別是子陣列的左端點和右端點 請問,好的子陣列的最大分數是多少?
題目會給們一個陣列,還有一個k值。 接著進行比大小的遊戲,規則如下: 每次取陣列前兩個元素值比大小,比較小的會被重新安排到陣列最後方,陣列前兩個元素值比大小,同樣的,比較小的會被重新安排到陣列最後方。依此類推,反覆進行比大小的遊戲。 請問第一個能連贏k回合的是哪個數字?
題目會給我們兩個陣列left, right 分別代表每隻螞蟻所在的初始位置 和 方向,n代表木板長度。每隻螞蟻每秒鐘前進一單位長度。 問我們,每隻螞蟻從初始位置出發,0秒起算,當兩隻螞蟻相遇時,會互相掉頭,往相反方向前進,問最後一隻螞蟻掉落木板的時候是幾秒鐘?
題目會給我們個陣列target,問我們從整數串流中1~n之中,如何透過stack 的 push和pop來模擬生成target指定的形式?
題目會給一顆二元樹,要求我們計算節點值 和 子樹平均值相等的node有幾個。
題目會給定一個字串s,裡面都是由()*打散交錯而成。 配對規則 左括弧 ( 可以和 右括弧 ) 配對,其中 左括弧一定要在右括弧的左邊。 左括弧 ( 也可以和 *星號 配對,其中 左括弧一定要在*星號的左邊。 問我們給定的輸入字串s是否為合法括弧配對字串?
題目會給們一個陣列,還有一個k值。 好陣列定義是: 有包含nums[k]的子陣列。 分數定義是: min(nums[i], nums[i+1], ..., nums[j]) * (j - i + 1) 其中, i, j 分別是子陣列的左端點和右端點 請問,好的子陣列的最大分數是多少?
題目會給們一個陣列,還有一個k值。 接著進行比大小的遊戲,規則如下: 每次取陣列前兩個元素值比大小,比較小的會被重新安排到陣列最後方,陣列前兩個元素值比大小,同樣的,比較小的會被重新安排到陣列最後方。依此類推,反覆進行比大小的遊戲。 請問第一個能連贏k回合的是哪個數字?
題目會給我們兩個陣列left, right 分別代表每隻螞蟻所在的初始位置 和 方向,n代表木板長度。每隻螞蟻每秒鐘前進一單位長度。 問我們,每隻螞蟻從初始位置出發,0秒起算,當兩隻螞蟻相遇時,會互相掉頭,往相反方向前進,問最後一隻螞蟻掉落木板的時候是幾秒鐘?
題目會給我們個陣列target,問我們從整數串流中1~n之中,如何透過stack 的 push和pop來模擬生成target指定的形式?
題目會給一顆二元樹,要求我們計算節點值 和 子樹平均值相等的node有幾個。
題目會給定一個字串s,裡面都是由()*打散交錯而成。 配對規則 左括弧 ( 可以和 右括弧 ) 配對,其中 左括弧一定要在右括弧的左邊。 左括弧 ( 也可以和 *星號 配對,其中 左括弧一定要在*星號的左邊。 問我們給定的輸入字串s是否為合法括弧配對字串?