貢獻者: 牙塑-Wind
🧔:interviewer
👶:interviewee
影片: 00:01
🧔:我這裡有一些近幾日的股價資料,每一份資料會是一段連續時間的股價變化,每天的股價都不太相同,我想請你幫我在這段連續時間內找出一組最大獲利
👶:好的,我想請問,一組最大獲利指的是在連續時間內哪一天買哪一天賣可以使得利益最大嗎,這些天數與股價的範圍有沒有什麼限制呢。
🧔:沒錯,請你找到在這段時間中,哪天買入哪天賣出可以獲得最大利益,請注意,必須先買股票才能賣出。天數範圍界在1 ~ 100000之間,股價界在 0 ~ 10000。
👶:那我會用python去實作想先請問一下,我是否能假設function的輸入為一個list
🧔:你可以假設輸入是一個list
👶:我想到的方法是,假設list名稱為prices,因為賣出股票前一定要先買股票,所以我可以設定兩個指標left與right分別設置在index0與index1的位置,left代表買入,right代表賣出,再來使用一個while迴圈遍歷list,每次迭帶去計算獲利,也就是prices[right]-prices[left],如果獲利為負數,表示賣出的數值比買入還要小,我們會希望買入的值可以盡量小,因此這時候可以把left指標移動到right的位置,right的指標加一,如果獲利為正,則去比較當前獲利與過去獲利的大小,並保留較大的獲利值,right指標加一去查看下一個數值。如此重複計算,迭帶到right指標遍歷完整個list,就可以終止迴圈並獲得最大獲利。
👶:這樣的作法時間複雜度為O(n),空間複雜度為O(1),以上為我的演算法。
🧔:OK,那請你用google document來實作這個題目。
👶:以上為我的演算法實作後的code,請問有什麼問題嗎?
🧔:你覺得這個題目存在時間複雜度更低的解法嗎?
👶:因為這是一個沒有排序的list,我想勢必要遍歷一次來確認所以值,才能找到最大獲利,因此我覺得最低的複雜度應該就是O(n)。
🧔:那你覺得你的程式碼還有什麼可以優化的地方嗎?
👶:我發現在每次while迴圈中,right都會加一,所以其實可以將迴圈改成使用for,這樣的好處在於,for的執行次數比較明確,再來是python code的效率是比較慢的,如果使用while迴圈,需要多right < len(prices)的邊界確認與right+=1這兩個步驟,使得while迴圈速度較慢。
🧔:你提到的邊界確認與變數加一的操作,for迴圈也需要進行不是嗎?
👶:是的,不過python底層是由C來實作,在for迴圈中,邊界確認與變數加一這兩個操作是底層的C做好的,所以會比使用while需要自己多兩這兩步驟的python code還要快。
🧔:了解,那請你把程式改成for迴圈的版本。
🧔:你是否能夠證明兩者的速度差異呢?
影片: 12:25
🧔:承接上一題,我們稍微改變一下題目,我一樣會給你一段連續時間的股價,這次要尋找的是整體的最大獲利,也就是在這段時間,我可以重複進行買跟賣,我們限制同一天只可以持有一張股票,不過可以在當天同時買跟賣。
👶:跟上一題一樣,我會拿到一個代表價格的陣列,但是不同於上一題只做一次買賣,這次不限買賣次數,但限制同一天只能持有一張股票,然後去尋找最大利益這樣嗎?
🧔:是的,沒錯。
👶:那請問天數與價格的範圍也都跟上一題一樣嗎?
🧔:是的,天數範圍界在1 ~ 100000之間,股價界在 0 ~ 10000。
👶:這題應該是要使用DP的想法來解,當前的最大獲利會根據於前一天的最大獲利計算得出,每一天我會有兩個狀態,持有股票跟沒持有股票,持有股票的狀態包括我原本就有持有股票沒賣出跟我把股票賣出今日買股票兩種,只要對這兩種情況取max計算最大收益,就可以計算今日持有股票可以獲得的最大收益。沒持有股票狀態包括,我原本就沒有持有股票跟我原本有持有但是今日賣掉了,同樣對這兩種情況取max,就可以獲得今日沒持有股票所得的最大收益。而最大利潤的情況會發生在最後一天沒有股票的狀態,因為把目前手中持有的股票賣掉才能獲得最大收益。
🧔:分析挺有道理的,那一樣請你用google document來實作這個題目。
👶:這樣的演算法,時間複雜度為O(n),空間複雜度為O(1)。
🧔:這題有更直觀更簡單的理解方式,時間複雜度同樣為O(n),空間複雜度為O(1),你可以想想你平常買賣股票的策略。
👶:我會希望在股價低的時候買入,價格上升的時候賣出。
🧔:而你現在已經可以知道在一段時間內股價的變化。
👶:我了解了,若把股價畫成折線圖,斜率正的區間為正收益的部分,只要將所有斜率為正的區間相加,即是最大收益。
👶:這樣演算法的時間複雜度與空間複雜度都跟使用DP作的方式相同,但是更為直觀,使用的變數也比較少。
影片: 20:28
🧔:Please implement a class called RandomizedSet that includes three operations: insert, remove, and getRandom. The insert operation inserts an item with the value into the set if it is not already present. It returns true if the item was not previously present, and false otherwise. The remove operation removes an item with the value from the set if it is present. It returns true if the item was previously present, and false otherwise. The getRandom operation returns a random element from the current set of elements. It is guaranteed that at least one element exists when this method is called, and each element in the set has an equal probability of being returned. You must implement the functions of the class such that each function works in average O(1) time complexity.
👶:So I need to define a class called RandomizedSet and implement three operations: insert, remove, and getRandom, all with a time complexity of O(1), while ensuring that these operations return the correct values. So, should I expect the input to be a series of operations?
🧔:That's correct. The input will be passed as a series of operations, and your class should correctly return boolean values or numbers as required. It's important to ensure that all your operations are completed in O(1) time complexity.
👶:To achieve O(1) time complexity for both insert and remove, I can utilize a hashmap data structure. I propose using a set as the data storage container, which would provide constant time complexity for both searching and the insert and remove operations. As for getRandom, I can use the random function to achieve the desired functionality.
🧔:Okay, please implement your class in a Google Document.
👶:This is the class I've implemented, and all three operations have O(1) time complexity.
🧔:Your insert and remove operations do indeed achieve O(1) complexity, but your random operation does not.
👶:Random.choice indeed has O(1) complexity, so converting a set to a list does not have O(1) complexity. So, I would need to maintain a list, but the issue is that when I perform a remove operation on the list, it still has O(n) complexity. I might need to use a dictionary to store the values and their corresponding indices in the list. Then, when I need to remove a value, I can swap it with the last element in the list and use pop to remove the last element. This way, the remove operation would also achieve O(1) complexity.
🧔:Great! Please go ahead and showcase your implementation.
👶:Using a combination of a list and a dictionary, it is possible to achieve O(1) time complexity for all three operations.
可以假裝在寫unit test把自己寫的function當做pure function來測試, fn (input).expect(output)
解釋解題思路清楚明確,且在撰寫程式碼時會同時解釋該段程式碼作用。
雖然使用python撰寫程式,但interviewee有同時說明底層實作的原理。
缺乏了舉例說明與程式碼可行性驗證的階段,interviewee一開始說明解題邏輯時沒有搭配畫面內容,稍顯可惜。