專欄 | 九章演算法
網址 | www.jiuzhang.com
題目描述
一群朋友去度假,有時互相借錢。
例如,愛麗絲為比爾的午餐支付了 10 美元。後來克里斯給愛麗絲 5 美元搭計程車。我們可以假設每筆交易為一個三元組(X,Y,Z),這意味著第 X 個人借給第 Y 個人 Z 美元。假設 Alice,Bill 和 Chris 是第0,1,2 個人(0,1,2是他們的ID),他們之間的交易可以表示為[ [ 0,1,10 ],[ 2,0,5 ] ]。
給定一組人之間的交易清單,返回結算所需的最低交易數量。
樣例 1
輸入 [[0,1,10], [2,0,5]]
輸出 2
樣例解釋
第 0 個人借給第 1 個人10美元
第 2 個人借給第 0 個人 5美元
需要2筆交易,其中一種方式是第1個人還給第0個人和第2個人各5美元。
樣例 2
輸入 [[0,1,10], [1,0,1], [1,2,5], [2,0,5]]
輸出 1
樣例解釋
第0個人借給第1個人10美元
第1個人借給第0個人1美元
第1個人借給第2個人5美元
第2個人借給第0個人5美元
只需要1筆交易,第1個人還給第0個人4美元債務就還清了。
解題思路
(一)
讀完題我們會發現每個人都有一個借錢的數量和一個還錢的數量(有可能是0),如果這個人的這兩個值的和為0,那麼他就不需要還錢或者借錢給別人了。
證明:假設此人在借還之和為0的情況下收到 X 的錢,那麼為了收支平衡,必定要把這些錢給另外一個人 Y,那麼這樣不會比X把錢直接給 Y 得到的答案更優。
比如,設三個人的收支情況為[-2,0,2],那麼第3個人把2轉移到第2個人,再由第2個人轉移到第1個人,需要2次交易,但是第3個人直接轉移給第1個人那麼只需要1次。
(二)
接下來我們只需要處理所有收支不為0的那些人。我們發現,(在資料合法的情況下)所有人的收支情況的和也是0,那麼我們就來分析一下如何讓答案最小。
對於預處理完收支情況的一個陣列 2 , 3 , -2 , -3 ,顯而易見答案是2 (2 → -2 , 3 → -3 ),但是還有一種不是最優的答案3(3 → -2 , 1 → -3 , 2 → -2)。那麼我們就能發現,最優答案是2個子問題([2,-2],[3,-3])的最優解的和。
我們可以用集合列舉所有的子集,找到每個子集的最優解從而解得總問題的最優解。在這裡我們可以把一個集合的子集定義為一個只有 0,1 的向量,
比如一個有3個元素的集合,他們的子集分別是000(空集),001,010,100,011,110,101,111(全集),'1'代表這個子集裡有這個元素,'0'代表這個子集裡沒有這個元素。
再利用一個1~n迴圈來判斷這個子集裡有哪些元素,如101代表這個子集裡有第1個和第3個元素。
(三)
接下來我們分析這種解法的時間複雜度,假設去除所有收支平衡以後的人數為n,列舉子集的時間複雜度為O(2^n),對每個子集進行最優解分析也需要列舉它的所有子集(這些子集的最優解已經計算完成),需要的時間複雜度也為O(2^n),最終的時間複雜度為O(4^n)。空間複雜度為O(2^n)。
參考程式碼
面試官角度分析
本題難度較大,可能會有多種解法,比如深度優先搜尋(需要列舉所有可能的交易情況)等,效率較低。
假如運用這種預處理+動態規劃或更高效的方法,那麼有 strong hire 的水平,如果能用其他解法(如搜尋)解出,則有 hire 的水平。
九章答案連結
LintCode 相關題目
k 數和: http://www.lintcode.com/zh-cn/problem/k-sum/
打劫房屋:www.lintcode.com/zh-cn/probl…
推薦閱讀:
- 《北美IT企業fulltime薪資大曝光》
- 《IT 簡歷模板大放送 | 《如何寫好技術簡歷》講座精華總結》
- 《offer收割機的求職祕訣 | <如何成為offer達人>講座精華總結》
- 《Google offer 如何談判?聽聽 Google recruiter 怎麼說!》
- 《面試遇到做過的題怎麼辦?》
- 《冷凍期大揭祕 | Google、FB、Amazon、Linkedin冷凍期》
- 《面試前如何瞭解一家IT企業?試試官方技術部落格!》
- 《北美IT企業intern薪資大曝光》
- 《16個behavior question 的面試官解析及tips》
- 《Google晉升機制 | 大公司如何升級打怪, 獲得晉升?》
歡迎關注我的微信公眾號:九章演算法(ninechapter)。
精英程式設計師交流社群,定期釋出面試題、面試技巧、求職資訊等