系統設計 設計一個平均O(1)的插入、刪除、隨機選擇元素的資料結構 Leetcode #380

更新於 發佈於 閱讀時間約 10 分鐘

題目敘述

題目會給我們一組定義好的界面和需求,要求我們設計一個資料結構,可以滿足平均O(1)的插入元素、刪除元素、隨機取得元素的操作。

RandomizedSet() 類別建構子

bool insert(int val) 插入元素的function界面

bool remove(int val) 刪除元素的function界面

int getRandom() 隨機取得元素的function界面

題目的原文敘述


測試範例

Example 1:

Input
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
Output
[null, true, false, true, 2, true, false, 2]

Explanation
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // Inserts 1 to the set. Returns true as 1 was inserted successfully.
randomizedSet.remove(2); // Returns false as 2 does not exist in the set.
randomizedSet.insert(2); // Inserts 2 to the set, returns true. Set now contains [1,2].
randomizedSet.getRandom(); // getRandom() should return either 1 or 2 randomly.
randomizedSet.remove(1); // Removes 1 from the set, returns true. Set now contains [2].
randomizedSet.insert(2); // 2 was already in the set, so return false.
randomizedSet.getRandom(); // Since 2 is the only number in the set, getRandom() will always return 2.

約束條件

Constraints:

  • -2^31 <= val <= 2^31 - 1

所有數值val落在-2^31 ~ 2^31 - 1 之間。

  • At most 2 * 105 calls will be made to insertremove, and getRandom.

對於insert(), revmoe(), getRandom(),做多有2 * 10^5動態測試呼叫。

  • There will be at least one element in the data structure when getRandom is called.

題目還保證,呼叫getRandom()時,會確保資料結構裡面至少存在一個元素。


演算法

根據需求的描述,要求平均O(1)的條件,滿直覺就會想到用字典來紀錄或者儲存元素。

比較困難的地方在於,還額外多了一個O(1) getRandom()的要求,相當於強迫我們一定要把每個元素存在一個線性的資料結構裡面,才有機會透過array[index]的方式達到Random access隨機讀取O(1)的要求。

此外,第二個比較特殊的地方在於,刪除的時候,同樣為了滿足O(1) remove()的要求,會先把被刪除的元素交換到array的尾端,再用pop的方式刪除掉。


程式碼

class RandomizedSet:

def __init__(self):
"""
Initialize your data structure here.
"""
# list to save numbers
self.number_list = []

# dictionary
# key: number
# value: index of number in self.number_list
self.number_dict = dict()

# size of data structure
self.size = 0


def insert(self, val: int) -> bool:
"""
Inserts a value to the set. Returns true if the set did not already contain the specified element.
"""


if val in self.number_dict:
return False

else:

# record new element index in dictionary
self.number_dict[ val ] = self.size

# append new element into list
self.number_list.append( val )

# update size of collection
self.size += 1

return True


def remove(self, val: int) -> bool:
"""
Removes a value from the set. Returns true if the set contained the specified element.
"""

if val not in self.number_dict:
return False

else:

# To reach O(1) performance, use technique of element swap, and pop on tail

# get the index of element with value
index_of_val = self.number_dict[val]


# update index of last_element
self.number_dict[ self.number_list[-1] ] = index_of_val


# swap val with last element of number_list
self.number_list[-1], self.number_list[index_of_val] = self.number_list[index_of_val], self.number_list[-1]


# remove val from list by popping last
self.number_list.pop()

# remove val from dictionary by deleting key
del self.number_dict[val]

# update size of collection
self.size -= 1

return True


def getRandom(self) -> int:
"""
Get a random element from the set.
"""

return random.choice( self.number_list )

複雜度分析

時間複雜度:

insert(), revmoe(), getRandom() 皆為平均O(1)的複雜度。

空間複雜度:

insert(), revmoe(), getRandom() 單獨一次操作也是O(1)。

全體來說,會需要一個O(n)的空間, n值由插入元素的總數量決定。


關鍵知識點

這題還有額外要求getRandom() O(1)的需求,因此用傳統的set()直接來儲存是無法滿足題目條件的。


Reference:

[1] Python by dict and list with swap [w/ Comment]

avatar-img
90會員
425內容數
由有業界實戰經驗的演算法工程師, 手把手教你建立解題的框架, 一步步寫出高效、清晰易懂的解題答案。 著重在讓讀者啟發思考、理解演算法,熟悉常見的演算法模板。 深入淺出地介紹題目背後所使用的演算法意義,融會貫通演算法與資料結構的應用。 在幾個經典的題目融入一道題目的多種解法,或者同一招解不同的題目,擴展廣度,並加深印象。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
題目敘述 題目會給定我們一個比賽紀錄陣列matches,裡面以pair的方式儲存,每個pair的第一個欄位代表這場比賽的贏家ID,第二個欄位代表這場比賽的輸家ID。 題目要求我們找出所有沒有輸的玩家ID,和只輸一場的玩家ID。 計算時,只考慮有比賽紀錄的玩家。 輸出時,依照遊戲玩家的ID,從
題目敘述 題目會給定我們兩個字串word1 和 word2。 允許我們不限制次數進行下列兩種操作: 任意調換其中兩個字元的位置。 把字串中的某個字元全部置換成另一個字元,同時把另一個字元同時置換成某個字元。(例如把字串中原本的a都換成b,把原本的b都換成a) 問我們能不能通過上述兩項操作,
題目敘述 題目會給我們兩個字串作為輸入,分別是字串s和字串t,問我最少要做幾次字元轉換,讓字串t和字串s成為Anagram"同字母異序詞"? 註: 例如 god 和 dog 就是 Anagram 同字母異序詞,也是就說,組成字母相同,但是順序可以重新排列。 題目的原文敘述 測試範例 Ex
題目敘述 題目會給我們一個輸入字串s,題目還保證字串s的長度一定是偶數。 要求我們判定字串s的前半部和後半部是否相似? 在本題中,兩個字串相似的定義為兩個字串都擁有相同的母音英文字母: 註: 母音英文字母為a, e, i, o, u, A, E, I, O, U 題目的原文敘述 測試
題目敘述 題目會給定我們一棵二元數Binary Tree的根結點。 問我們任意祖先節點和晚輩節點之間,最大的差值的絕對值是多少? 題目的原文敘述 測試範例 Example 1: Input: root = [8,3,10,1,6,null,14,null,null,4,7,13] Ou
題目敘述 題目會給定我們一棵二元數Binary Tree的根結點。 並且給定感染的病毒源節點位置,每個單位時間,可以向相鄰的節點感染一次,問我們需要多少時間去感染整棵樹? 題目的原文敘述 測試範例 Example 1: Input: root = [1,5,3,null,4,10,6,
題目敘述 題目會給定我們一個比賽紀錄陣列matches,裡面以pair的方式儲存,每個pair的第一個欄位代表這場比賽的贏家ID,第二個欄位代表這場比賽的輸家ID。 題目要求我們找出所有沒有輸的玩家ID,和只輸一場的玩家ID。 計算時,只考慮有比賽紀錄的玩家。 輸出時,依照遊戲玩家的ID,從
題目敘述 題目會給定我們兩個字串word1 和 word2。 允許我們不限制次數進行下列兩種操作: 任意調換其中兩個字元的位置。 把字串中的某個字元全部置換成另一個字元,同時把另一個字元同時置換成某個字元。(例如把字串中原本的a都換成b,把原本的b都換成a) 問我們能不能通過上述兩項操作,
題目敘述 題目會給我們兩個字串作為輸入,分別是字串s和字串t,問我最少要做幾次字元轉換,讓字串t和字串s成為Anagram"同字母異序詞"? 註: 例如 god 和 dog 就是 Anagram 同字母異序詞,也是就說,組成字母相同,但是順序可以重新排列。 題目的原文敘述 測試範例 Ex
題目敘述 題目會給我們一個輸入字串s,題目還保證字串s的長度一定是偶數。 要求我們判定字串s的前半部和後半部是否相似? 在本題中,兩個字串相似的定義為兩個字串都擁有相同的母音英文字母: 註: 母音英文字母為a, e, i, o, u, A, E, I, O, U 題目的原文敘述 測試
題目敘述 題目會給定我們一棵二元數Binary Tree的根結點。 問我們任意祖先節點和晚輩節點之間,最大的差值的絕對值是多少? 題目的原文敘述 測試範例 Example 1: Input: root = [8,3,10,1,6,null,14,null,null,4,7,13] Ou
題目敘述 題目會給定我們一棵二元數Binary Tree的根結點。 並且給定感染的病毒源節點位置,每個單位時間,可以向相鄰的節點感染一次,問我們需要多少時間去感染整棵樹? 題目的原文敘述 測試範例 Example 1: Input: root = [1,5,3,null,4,10,6,
你可能也想看
Google News 追蹤
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
一月五日開始播放!深入大河劇《大膽狂徒》的和服設計幕後   以天下太平、文化興盛的江戶時代中期為舞台,描寫人稱「日本的媒體王」馳騁時代的豪邁男子・蔦屋重三郎生平的大河劇《大膽狂徒~蔦重榮華乃夢新~》,即將登場。 點綴這部眾所矚目的連續劇的,是反映出江戶時代的美感與文化的眾多和服。這次擔任服裝設
Thumbnail
這篇內容,將會講解什麼是資料型態,以及與資料型態相關的知識。包括資料型態的簡介、實數、布林值、 字串、陣列。
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
本文(5萬兩千多字)是Ra Uru Hu講解關於人類設計中罕見的生物設計圖(Biology Design Chart),主要是涉及閘門與身體健康狀態的各個關聯器官及其醫療臨床應用。這些蠻實用的醫療資訊,平常的課程內容中較為少見。
Thumbnail
LeetCode 是一個程式語言版的線上題庫平臺,提供題目描述、程式碼區塊、解題者分享的解法和疑問討論。藉由這篇文章分享我在 LeetCode 上的使用經驗和觀點,包括刷題的重要性、解題心態和練習目標。
Thumbnail
魔鬼藏在二分搜尋裡!輸出值代表的意含、題意產生的邊界條件,寫完模板才是挑戰的開始 Orz
Thumbnail
列出一套完整的程式 程式設計有許多種方法,不過通常會先列出清單的再逐一執行,這樣會加快程式設計的速度。設計通常會採取順推的辦法。所以順推的程式設計方式就是經歷觀念溝通、系統分析、資料統合、權限管理、頻率與時間、後台管理、畫面設計等等階段後,將框架設計完了以後,先列出一套完整的程式,將所有使用者都確
Thumbnail
程式設計中不可或缺的一部分 介面是使用者與程式互動的媒介,因此介面的設計會影響使用者的體驗和感受。一個清晰明白、易懂的介面,可以讓使用者輕鬆地使用程式,並獲得良好的使用體驗。 需要與程式設計師密切溝通 設計師需要了解程式的功能和需求,並根據使用者的習慣和需求進行設計。設計師和程式設計師之間的溝
Thumbnail
題目敘述 題目會給我們一個定義好的類別和function介面,要求我們實作建構子和ping() function來滿足指定的需求。 RecentCounter類別的建構子 建構子應該初始化來電紀錄,內容為空(零筆資料) int ping(int t) t代表來電時刻,單位是毫秒m
Thumbnail
中津川市位於岐阜縣東南端,東臨木曾山脈,南臨三河高原,木曾川流經市中心,以恵那山為象徵,是一座歷史悠久四面環山自然豐富的城市,東西長28公里,南北長49公里,總面積676.45平方公里。昔日作為東山道、中山道、飛驒街道的交通樞紐而繁榮,隨著核心產業園區的建成,許多企業入駐於此,逐漸發展成為商工業都市
Thumbnail
隨著理財資訊的普及,越來越多台灣人不再將資產侷限於台股,而是將視野拓展到國際市場。特別是美國市場,其豐富的理財選擇,讓不少人開始思考將資金配置於海外市場的可能性。 然而,要參與美國市場並不只是盲目跟隨標的這麼簡單,而是需要策略和方式,尤其對新手而言,除了選股以外還會遇到語言、開戶流程、Ap
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
一月五日開始播放!深入大河劇《大膽狂徒》的和服設計幕後   以天下太平、文化興盛的江戶時代中期為舞台,描寫人稱「日本的媒體王」馳騁時代的豪邁男子・蔦屋重三郎生平的大河劇《大膽狂徒~蔦重榮華乃夢新~》,即將登場。 點綴這部眾所矚目的連續劇的,是反映出江戶時代的美感與文化的眾多和服。這次擔任服裝設
Thumbnail
這篇內容,將會講解什麼是資料型態,以及與資料型態相關的知識。包括資料型態的簡介、實數、布林值、 字串、陣列。
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
本文(5萬兩千多字)是Ra Uru Hu講解關於人類設計中罕見的生物設計圖(Biology Design Chart),主要是涉及閘門與身體健康狀態的各個關聯器官及其醫療臨床應用。這些蠻實用的醫療資訊,平常的課程內容中較為少見。
Thumbnail
LeetCode 是一個程式語言版的線上題庫平臺,提供題目描述、程式碼區塊、解題者分享的解法和疑問討論。藉由這篇文章分享我在 LeetCode 上的使用經驗和觀點,包括刷題的重要性、解題心態和練習目標。
Thumbnail
魔鬼藏在二分搜尋裡!輸出值代表的意含、題意產生的邊界條件,寫完模板才是挑戰的開始 Orz
Thumbnail
列出一套完整的程式 程式設計有許多種方法,不過通常會先列出清單的再逐一執行,這樣會加快程式設計的速度。設計通常會採取順推的辦法。所以順推的程式設計方式就是經歷觀念溝通、系統分析、資料統合、權限管理、頻率與時間、後台管理、畫面設計等等階段後,將框架設計完了以後,先列出一套完整的程式,將所有使用者都確
Thumbnail
程式設計中不可或缺的一部分 介面是使用者與程式互動的媒介,因此介面的設計會影響使用者的體驗和感受。一個清晰明白、易懂的介面,可以讓使用者輕鬆地使用程式,並獲得良好的使用體驗。 需要與程式設計師密切溝通 設計師需要了解程式的功能和需求,並根據使用者的習慣和需求進行設計。設計師和程式設計師之間的溝
Thumbnail
題目敘述 題目會給我們一個定義好的類別和function介面,要求我們實作建構子和ping() function來滿足指定的需求。 RecentCounter類別的建構子 建構子應該初始化來電紀錄,內容為空(零筆資料) int ping(int t) t代表來電時刻,單位是毫秒m
Thumbnail
中津川市位於岐阜縣東南端,東臨木曾山脈,南臨三河高原,木曾川流經市中心,以恵那山為象徵,是一座歷史悠久四面環山自然豐富的城市,東西長28公里,南北長49公里,總面積676.45平方公里。昔日作為東山道、中山道、飛驒街道的交通樞紐而繁榮,隨著核心產業園區的建成,許多企業入駐於此,逐漸發展成為商工業都市