鴿巢原理詳解


鴿巢原理

假設我們有 10 只鴿子,但只有 9 個鴿籠可以放入它們。由於我們的鴿子比鴿籠多,因此至少其中一個洞必須至少有 2 只鴿子。 這就是鴿巢原理。 每當我們要放入孔中的物品多於孔時,至少一個孔必須包含不止一件物品。

假設鴿子的數為n,鴿籠的個數為k,那么上述原理轉換下就是: 鴿巢原理

假設你有 k 個鴿籠和 n 只鴿子要放在里面。 如果 n > k (鴿子數 > 鴿籠數) 那么至少一個鴿舍包含至少兩只鴿子。

其中,鴿子通常是數字、物體乃至一個對象,而鴿籠則是存儲數組、物體或者對象的一個容器。

證明

我們第一反應是,這不是顯而易見的么?還需要證明?

想象一下,一群鴿子被塞進了許多抽屜。 只要鴿子的數量超過抽屜的數量,至少一個抽屜會包含兩只鴿子。 請注意,即使在最平等的情況下,每個抽屜都有一只鴿子,但最后仍有剩余的鴿子需要放入其中一個已經裝滿的抽屜,從而實現原則。 如果鴿子是按概率分布的,當然有些抽屜里可能會有超過兩只鴿子。

在一般情況下,如果將 n 個對象放入 m 個容器中,則:

  • 如果n < m,則有部分容器是空的
  • 如果 n > m, 則有部分容器至少有兩個對象 那么轉換成公式就是:

n = (r - 1)m + 1

或者

r = [(n - 1) / m] + 1 = ROUNDUP(n / m)

其中:

n 為鴿子或者對象的數量 m 為鴿巢或者容器的數量 r 為容器或者鴿巢中 最多的對象或者鴿子的數量

假設 n < m 並且存在從 Nm = {1, ..., m} 到 Nn = {1, ..., n} 的函數 f。 這意味着,對於每個 k∈Nm,都有一個元素 f(k)∈Nn。 此外,假設 Nn 中沒有任何元素與 Nm 中的一個以上元素相關聯。 換句話說,i,j∈Nm 和 i≠j 意味着 f(i)≠f(j)。 這恰恰意味着 f(Nm) 是 Nn 的子集,使得 m = |f(Nm)| = |Nm| ≤ |Nn| = n。 但這與我們的假設 n

應用

以leetcode第442題為例

分析:

n個巢, n+1只鴿子,每個鴿子進一個巢,那種總會剩下一個鴿子無家可歸; 在此問題中我們假設數字的下標為鴿巢,下標對應的值為鴿子編號。 經過一次遍歷讓鴿子(回到鴿子編號-1的巢里)回家,最終發現無家可歸的鴿子,和沒有鴿子的巢。

代碼實現:

vector findDisappearedNumbers(vector& nums) {
        int n=nums.size();
        for(int i=0;i<n;i++)
        {
            while(nums[i]!=nums[nums[i]-1])
                swap(nums[i],nums[nums[i]-1]);
        }     
        vector res;
        for(int i=0;i<n;i++)
        {
            if(nums[i]!=i+1)
                res.push_back(nums[i]);
        }   
        return res;
    }


專注於高性能架構探索與開發,關注公眾號【高性能架構探索】,一起進步



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM