top k問題是指給定一組數量為n的數,從中找出前k大的數或第k大的數(k <= n)。由於只要能找出前k大的數,即可以得到第k大的數。所以下面先介紹解決前k大數問題的幾種思路:
由於我們只需要找到陣列nums的前k大的數,所以不需要對整個資料進行排序,只需要保持前k大的數有序即可。所以我們可以維護乙個大小為k的陣列tk:
複雜度:對tk排序的複雜度為o(k*logk),向tk插入資料的複雜度為o(k), 所以遍歷陣列nums並向tk插入資料的複雜度為o(n*k),總的複雜度為o(k*logk + n*k) 近似為 o(k*n)
如果k的值過大,演算法的複雜度會相應增大
**
vector
solve1(vector
&nums, int k)
tk[j] = tk[j-1];
j--;
}if(j == 0)
tk[j] = t;}}
return tk;
}
我們可以將待找陣列nums建立為乙個大根堆,然後從建好的堆中一次找出最大的k個數即可。
複雜度:使用篩選法建堆的複雜度為o(n), 然後從大根堆中找出前k大數的複雜度為o(k*logn),所以總的複雜度為:o(n + k*logn)
顯然這個演算法的複雜度要低於部分排序。
**
vector
solve2(vector
&nums, int k)
return result;
}void adjust(vector
&nums, int i, int n)
nums[parent] = t;
}
分析前面的部分排序演算法,我們可以發現有太多的時間浪費在了對陣列tk的插入操作中,為了提高插入的效率,我們可以將陣列tk組織為乙個小根堆,對於小根堆的插入操作複雜度為o(logk),這顯然要優於直接插入的複雜度o(k)。
複雜度:總的複雜度為 o(n*logk)
**
vector
solve3(vector
&nums, int k)
//對tk排序
for(int i = k-1; i >= 0; i--)
return tk;
}void adjust(vector
&nums, int i, int n)
nums[parent] = t;
}
還有一種演算法是基於快速排序的,我們知道每趟快排都會選定乙個基準值,一趟快排後,基準值右邊的所有數都大於這個基準值,所以我們可以通過選取合適的部分遞迴地對這些部分進行一趟快排,直到基準值右邊的數為k個,那麼我們就得到了陣列的前k大的數:
1. 首先對陣列nums進行一趟快排
2. 然後根據關鍵值key的位置進行判斷
3. 如果key的下標 i < n-k : 對i右邊的部分進行一趟快排,然後重複步驟2
4. 如果key的下標 i > n-k : 對i左邊的部分進行一趟快排,然後重複步驟2
5. 如果key的下標 i == n-k ,那麼就返回key(或 i )
上述算中,如果返回key就是陣列中第k大的數,如果返回i就是前k大數的位置,下面的演算法給出的是乙個尋找第k大數的演算法,稍作修改就可以得到前k大的數。
複雜度:o(n)
**
int qselect(vector
&nums, int left, int right, int k)
nums[low] = key;
if(low == nums.size()-k)
return key;
else
if(low < nums.size()-k)
return qselect(nums, low+1, right, k);
else
return qselect(nums, left, low-1, k);
}}
repo init失敗的幾種解決方法
試了幾天,終於解決了同步repo init失敗的問題。謹此記錄一下。希望對讀者有用。由於每個人的情況都不一樣。所以我這裡會列舉我嘗試的所有方法。注意repo sync的問題不在本文討論的範圍內。mac,10.15 0s,git 目錄下有.repo資料夾。在這個資料夾下包含 error ssl cer...
Hash衝突的幾種解決方法
1.開放定值法 也叫再雜湊法,當關鍵字key的雜湊位址p h key 出現衝突時,以p為基礎,產生另乙個雜湊位址p1,如果p1仍然衝突,再以p為基礎,產生另乙個雜湊位址p2,直到找出乙個不衝突的雜湊位址pi 將相應元素存入其中。通常都是用以下公式計算 hi h key di m i 1,2,n 其中...
java解決topk問題
面試題中經常用到堆,這裡總結一下。方法一 對源資料中所有資料進行排序,取出前k個資料,就是topk。但是當資料量很大時,只需要k個最大的數,整體排序很耗時,效率不高。方法二 維護乙個k長度的陣列a,先讀取源資料中的前k個放入陣列,對該陣列進行公升序排序,再依次讀取源資料第k個以後的資料,和陣列中最小...