2014-05-26
程式猿【問題描述】
昨天我在整理從洗衣店洗乾淨的一堆襪子,發現我用的方法非常不高效。我用了乙個最簡單的方法:拿到乙隻襪子,然後從頭到尾去找另外乙隻襪子。用這種方法需要重複平均超過 n/2*n/4=n2/8 雙襪子。
作為乙個計算機科學家,我在想我應該怎麼做?我立馬就想到了根據尺寸顏色排序來得到乙個複雜度為o(nlogn)的方法。
雜湊或其他「非原地」的方法在這裡不可取,因為我不可能複製襪子(要是可以的話就好了)。
因此,這個基本問題是:
給一堆襪子,總數 n 雙,即包含 2n 只襪子(襪子是亂放的,即不是成對放的),假設每只襪子都有乙個確定的且能和它配對的襪子,問:如何用最快最有效的演算法找出每只襪子與之配對的另乙個襪子,並且最多使用對數級別的額外空間?
如果答案能夠考慮到下面的幾個方面,我會非常高興:(我希望答案能夠考慮到下面的幾個方面:)
1.該演算法要同樣適用於巨大數量的襪子。
2.現實中襪子數量不會很多,我和我配偶的襪子加起來不超過30雙(我們倆的襪子非常容易區分,這可以被利用嗎?)
3.該問題是否等同於元素唯一性問題(element distinctness problem)?
【最佳答案】
上面提到的排序雖然可以考慮,但是有點浪費。因為我們不需要有序,我們僅僅需要的是具有「相同」屬性的東西;
因此雜湊演算法就已經足夠了,並且還很快。
1.從另乙個角度來看堆(一堆襪子)是由襪子的所有顏色形成的。所以遍歷輸入籃子中的所有襪子並,根據顏色再把他們放到不同的籃子。
2.遍歷上述新形成的每個籃子,再根據其他的一些特性比如形狀將襪子放到第二個集合籃子中。
3.遞迴地運用上述方法,直到將所有襪子都放到乙個非常小的籃子中,最後你可以很容易的來處理。
sql server的實現就採用的是這種遞迴雜湊劃分方法,當它要進行新增或者合併巨大集合的時候。它將輸入劃分成了多個集合,而且每個集合都是相互獨立的。這個方法對任意資料量和多核cpu都可以得到線性的複雜度。
如果你可以找到乙個值,使得每個籃子內的元素數量小到可以很輕鬆處理的程度,那麼你就可以不用遞迴的劃分。不幸的是,我認為襪子沒有這樣的乙個屬性。
如果每個襪子都有乙個整數形式的」pairid」,這樣就可以很容易依據雜湊演算法pairid%10,將所有襪子放到10個籃子中。
我認為實際上最有效的劃分是:用乙個長方形的盒子,長方形的一條邊代表顏色,另一條邊代表形狀。(譯者注:運用乙個二位陣列,一維代表顏色,另一維代表形狀)。為什麼是乙個長方形的盒子?因為這樣我們可以只用o(1)的代價,就可以隨機訪問盒子中的元素。(三維的長方體也可以,但是不合實際)。
【答案更新】
考慮並行處理呢?如果有多個人來共同配對襪子,是否會快點呢?
1.有乙個最簡單的並行策略,就是多個工人共同處理一籃子的襪子,將襪子配對。這只會加快一點點,假設有100個人處理10堆襪子。多人之間的同步成本(比如說手工碰撞和人類溝通)這樣會降低效率和速度(見universal scalability law)。這樣會導致死鎖嗎?不會,因為每乙個工人在乙個時間只會訪問乙個籃子。只需要乙個鎖就可以防止死鎖。是否發生活鎖(livelocks)則依賴於工人怎麼合作去訪問籃子。他們可能使用類似網絡卡那樣的二進位制指數退避演算法(random backoff ),在物理級別上決定哪些可以獨佔的訪問網線。如果這個方法在網絡卡上有成效,那也同樣適用於那些工人。
2. 如果每個工人都有自己的乙個籃子集合那這個規模就會接近無限大了。工人們可以從乙個非常大的籃子中拿走襪子,並且在配對所有襪子時候不需要相互交流同步(因為此時每個人都有自己獨有的籃子)。最後再將每個工人所有的籃子合併在一起。我認為如果所有工人能夠形成乙個聚合樹,那麼這個問題可以在複雜度o(logw*p) (w代表工人的數量,p是平均每個工人的堆數量)內完成。
元素唯一性會如何呢?前文也提到了,元素唯一性可以在o(n)內解決。如果你只需要乙個分派步驟(我之前推薦分發多次,是因為人計算能力不強的原因。如果你使用md5來進行分發,一次就足夠了。因為md5可以把顏色、長度、圖案都考慮進去,是乙個包含所有屬性的完美雜湊),襪子問題同樣也可以在o(n)內處理完。
很明顯,所有演算法最快也不可能超過o(n),所以我們達到了最優下界。
儘管輸出可能不完全相等(在一種情況下,只是乙個布林值。另一種情況,是一雙襪子),但是漸進複雜性確實相等的。
如何用vue cli快速搭建乙個vue專案
如何用vue cli快速搭建乙個vue專案 vue cli是vue的腳手架。腳手架就是工地上為了保證各施工過程順利進行而搭設的工作平台,vue cli用來快速搭建乙個vue專案。我在桌面建立乙個vuetest資料夾,然後用vs code開啟該資料夾 ctrl 加 鍵開啟終端,輸入npm v 檢視no...
如何從一堆數中選出若干個數,使其和等於給定的數?
如題,比如有一堆數 13,2,4,2,4,8,7,8,6 要從中挑選出若干個數,使得它們的和等於32,挑選出來的數是 20,6,4,2 我是使用 試探 法來解這個題目,思路如下 先對數進行排序 13,8,8,7,6,4,4,2,2 選出最大的數字,以及不大於目標數字後續數字,於是我挑選到了13,8,...
如何用Python快速開發乙個企業微信群機械人?
在機械人的屬性上,有乙個webhook位址鏈結,格式為 其中key對應的值就是我們要記錄的值 在下面的 裡會用到 import requests headers 注意這段key一定要妥善保護 不能暴露到外部空間 否則安全隱患很多 params key 123456 456789 156486 dat...