N個數(shù)取Top K的平均復雜度O(N)的算法

n個數(shù)選top k,可以用快排剪枝來做捅膘。也就是說添祸,進行一輪比較,給第n個數(shù)找位置(前面的都比它小寻仗,后面的都比它大)刃泌,如果找到的位置i在k前面,就在i+1到n之間找top k-i署尤;如果i在k后面蔬咬,就在1到i-1之間找top k。
網(wǎng)上說算法復雜性是O(N)沐寺,我感覺這也太快了林艘。但是我不會證,既證明不了是O(N)混坞,也證明不了不是狐援。于是寫了個程序钢坦,畫個圖。視覺上看啥酱,應該是O(N)爹凹,因為太直線了也。

public class TopK {

private int n, k;
private double[][] nSelK = null;    // Only k*(n-k) elements are eventually computed.

public TopK(int n, int k){
   this.n = n;
   this.k = k;
}

/**
 * @return Return this for convenience.
 */
public TopK compute() {
    nSelK = new double[n][n];
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            nSelK[i][j] = -1.0;
        }
    }
    counts(n, k);
    return this;
}

/**
 * Average counts of comparison when selecting top k from n.
 * Only k >= 1 and n >= k is valid.
 */
private double counts(int n, int k) {
    double r = nSelK[n-1][k-1];
    if (r < 0) {    // Get in first time. Compute.
        r = 0.0;
        if (n == 1 && k == 1) {
        } else {
            for (int i = 1; i < k; i++)  {
                r += counts(n - i, k - i);
            }
            for (int i = k + 1; i <= n; i++) {
                r += counts(i - 1, k);
            }
            r = r/n + n-1;
        }
        nSelK[n-1][k-1] = r;
    //   System.out.printf("Got %d-%d: %f: \n", n, k, r);
    }
    return r;
}

public void printCol() {
    for (int i = k; i <= n; i++) {
        System.out.printf("%d\t%d\t%f \n", i, k, nSelK[i - 1][k - 1]);
    }
}

public void printAll() {
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= i; j++) {
            System.out.printf("%.2f\t", nSelK[i - 1][j - 1]);
        }
        System.out.println();
    }
}

public static void main(String[] args) {
    int n = 100, k = 5;
    new TopK(n, k).compute().printCol();
}
}

跑出來的結(jié)果是:


top5(n=100).png

n k comparison counts
5 5 5.433333
6 5 8.333333
7 5 11.185714
8 5 13.954762
9 5 16.646032
10 5 19.270635
11 5 21.838961
12 5 24.359668
13 5 26.839777
14 5 29.284965
15 5 31.699850
16 5 34.088220
17 5 36.453211
18 5 38.797446
19 5 41.123134
20 5 43.432155
21 5 45.726120
22 5 48.006420
23 5 50.274260
24 5 52.530697
25 5 54.776658
26 5 57.012962
27 5 59.240336
28 5 61.459428
29 5 63.670820
30 5 65.875031
31 5 68.072534
32 5 70.263754
33 5 72.449077
34 5 74.628856
35 5 76.803413
36 5 78.973041
37 5 81.138011
38 5 83.298571
39 5 85.454951
40 5 87.607364
41 5 89.756004
42 5 91.901054
43 5 94.042683
44 5 96.181048
45 5 98.316298
46 5 100.448567
47 5 102.577986
48 5 104.704674
49 5 106.828744
50 5 108.950302
51 5 111.069448
52 5 113.186275
53 5 115.300871
54 5 117.413321
55 5 119.523704
56 5 121.632093
57 5 123.738560
58 5 125.843171
59 5 127.945991
60 5 130.047079
61 5 132.146492
62 5 134.244286
63 5 136.340512
64 5 138.435220
65 5 140.528456
66 5 142.620266
67 5 144.710693
68 5 146.799778
69 5 148.887560
70 5 150.974076
71 5 153.059363
72 5 155.143455
73 5 157.226385
74 5 159.308185
75 5 161.388885
76 5 163.468513
77 5 165.547100
78 5 167.624670
79 5 169.701251
80 5 171.776867
81 5 173.851541
82 5 175.925298
83 5 177.998160
84 5 180.070147
85 5 182.141282
86 5 184.211583
87 5 186.281069
88 5 188.349761
89 5 190.417675
90 5 192.484829
91 5 194.551240
92 5 196.616924
93 5 198.681897
94 5 200.746174
95 5 202.809769
96 5 204.872698
97 5 206.934974
98 5 208.996610
99 5 211.057620
100 5 213.118015

看到結(jié)果后我反而會證了镶殷。因為顯然斜率不超過4禾酱,并且過原點,也就是說只要證明比較次數(shù)f(n) < 4n绘趋,就證明了復雜度是O(n)的颤陶。歸納,已知f(n,k) < 4n對所有n=1到s-1及任何k<=n都成立陷遮,計算f(s,k) = s-1 + (1/s) * (f(s-1,k-1) + f(s-2,k-2) + ...... + f(s-k+1,1) + f(k+1,k) + f(k+2,k) + ...... + f(s-1,k)),按照歸納搅方,其中
f(s-1,k-1) + f(s-2,k-2) + ...... + f(s-k+1,1) < 4(s-1) + 4(s-2) + ...... + 4(s-k+1) = 2(2s-k)(k-1)
f(k+1,k) + f(k+2,k) + ...... + f(s-1,k) < 4(k+1) + 4(k+2) + ...... + 4(s-1) = 2(s+k)(s-k-1)
這樣吧慢,f(s,k) < s-1 + (1/s) * (2(2s-k)(k-1) + 2(s+k)(s-k-1)) = s-1 + (1/s)(2ss+4sk-4kk-6s) = s-7 + (1/s)(2ss+4sk-4kk)
其中2ss+4sk-4kk=-4(k-s/2)(k-s/2) + 3ss底哗,在k=s/2時涕癣,取得最大值3ss坠韩。這樣俭尖,
f(s,k) < s-7 + (1/s)*3ss = 4s-7 < 4s焰望。
[證畢]
跑了多個參數(shù)来屠,肉眼看f(n)沒有超過3n的足陨,所以有可能f(n)<3n也能證出來。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蝶棋,一起剝皮案震驚了整個濱河市玩裙,隨后出現(xiàn)的幾起案子兼贸,更是在濱河造成了極大的恐慌,老刑警劉巖吃溅,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件溶诞,死亡現(xiàn)場離奇詭異,居然都是意外死亡决侈,警方通過查閱死者的電腦和手機其垄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門干像,熙熙樓的掌柜王于貴愁眉苦臉地迎上來聚凹,“玉大人芜壁,你說我怎么就攤上這事÷耄” “怎么了孽亲?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長展父。 經(jīng)常有香客問我墨林,道長赁酝,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任旭等,我火速辦了婚禮酌呆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘搔耕。我一直安慰自己隙袁,他們只是感情好,可當我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布弃榨。 她就那樣靜靜地躺著菩收,像睡著了一般。 火紅的嫁衣襯著肌膚如雪鲸睛。 梳的紋絲不亂的頭發(fā)上娜饵,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音官辈,去河邊找鬼箱舞。 笑死,一個胖子當著我的面吹牛拳亿,可吹牛的內(nèi)容都是我干的晴股。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼肺魁,長吁一口氣:“原來是場噩夢啊……” “哼电湘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起鹅经,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤寂呛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后瘾晃,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贷痪,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年酗捌,在試婚紗的時候發(fā)現(xiàn)自己被綠了呢诬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片涌哲。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡胖缤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出阀圾,到底是詐尸還是另有隱情哪廓,我是刑警寧澤,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布初烘,位于F島的核電站涡真,受9級特大地震影響分俯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜哆料,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一缸剪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧东亦,春花似錦杏节、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至壮啊,卻和暖如春嫉鲸,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背歹啼。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工玄渗, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人染突。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓捻爷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親份企。 傳聞我的和親對象是個殘疾皇子也榄,可洞房花燭夜當晚...
    茶點故事閱讀 44,947評論 2 355

推薦閱讀更多精彩內(nèi)容