3.7 實戰(zhàn)解題:哪個數(shù)字超過了一半

Chapter3: 更好的查找與排序算法

7. 實戰(zhàn)解題:哪個數(shù)字重復數(shù)超過了數(shù)組一半長度腊尚?

題目

數(shù)組中有一個數(shù)字出現(xiàn)的次數(shù)超過了數(shù)組長度的一半消别,找出這個數(shù)字豪嗽。

算法

分析:因為這個數(shù)字k出現(xiàn)次數(shù)超過了N/2像寒,注意利用這個特性這意味著:

  • 如果數(shù)組排好序的話疼邀,第N/2個元素一定是這個數(shù)字
  • 這個數(shù)k的出現(xiàn)次數(shù)比所有其它元素加起來的還要多。

解法1

思路

hash統(tǒng)計陕凹,hashmap 沒學悍抑,之后再說

解法2

思路

排序后返回arr[N/2] 鳄炉,時間復雜度為快排的時間復雜度 O(nlgn)

解法3

思路

與上一題找k類似杜耙,其實不需要將全部數(shù)組排好序,進行一次快排的劃分即可拂盯,此時 arr[N/2] 即為所求的數(shù)佑女, 時間復雜度為 O(n)

快排的雙向掃描分區(qū)法的代碼參考上一篇文章

解法4

思路

如果一個數(shù)出現(xiàn)的次數(shù)超過數(shù)組一半的長度,那么就是說出現(xiàn)的次數(shù)比其他所有數(shù)字出現(xiàn)的次數(shù)還要多谈竿。

  • 設置2個變量 valuecount 团驱,value 代表元素的值,初始化為第一個元素值空凸,count 代表某元素值的出現(xiàn)次數(shù)嚎花,初始化為1

  • for循環(huán)遍歷數(shù)組,如果下一個元素的值與 value 的值相同,則 count++ 呀洲,否則count-- , 當count==0 時紊选,將value 設置為下一個元素值并將count值設為1

    當count==0時,網(wǎng)上的代碼都是跳過了與 value使之為0的那個數(shù)道逗,將下下位賦值給 value

    比如數(shù)組里第一個數(shù)和第二個數(shù)不同的話兵罢,按照網(wǎng)上代碼的走法就會跳過第二個值,強迫癥的我感覺每個元素都要賦值給 value 比較過才對滓窍,只需在 if(count==0) 的條件下卖词,i-- 回退一位即可

    至于為什么跳過也可以,以"第2個元素與第1個元素不同"這種情況來說吏夯,第2個元素使得 count變?yōu)?,即相當于第2個元素與第1個元素對消此蜈,如果按照網(wǎng)上的代碼跳過了第2個元素

    • 如果第2個元素是其它元素即横,則對結(jié)果沒有影響;
    • 如果第2個元素就是要找的元素裆赵,因為要找的元素 k 數(shù)量是大于N/2的令境,所以就算剛好只有[N/2]+1個,并且其它元素與 k一一對消 ,與也會剩下一個k顾瞪,所以跳過對結(jié)果沒有影響

    debug的過程真是艱辛啊┭┮﹏┭┮

  • 因為要找的數(shù)字出現(xiàn)的次數(shù)比其他所有的數(shù)字出現(xiàn)的次數(shù)之和要大舔庶,所以遍歷完數(shù)組,最后必然count>=1陈醒, 并且 value 的值就是要找的值

代碼
int findK(int* arr,int arrLen){
    int value=arr[0];
    int count=1;
    for(int i=1;i<arrLen;i++){

        if(count==0){
            i--;//避免value的賦值跳過那個使count等于0的與value比較的數(shù)組元素 ,網(wǎng)上其它人的代碼就是少了這條語句
            value=arr[i];
            count++;
        }

        else{
            if(value==arr[i])//count!=0 && value==arr[i] 
                count++;
            else//count!=0&value!=arr[i]
                count--;
        }
    }
    return value;
}
debug過程記錄

一開始發(fā)現(xiàn)網(wǎng)上的代碼是跳過之后惕橙,也沒有仔細思考可行性,就試著驗證一下把第2個元素設置為要找的值 k 钉跷,結(jié)果出錯了弥鹦,找了另一個出現(xiàn)次數(shù)比 k 少1次的數(shù),就以為自己的想法是正確的爷辙,因為跳過了一個k

于是就額外寫了個判斷語句彬坏,使得不跳過第二個數(shù),運行結(jié)果就正確了膝晾,科十自己又想栓始,跳過也不是只是第二個數(shù)跳過啊,自己在腦海里演練了一下血当,發(fā)現(xiàn)使得 count==0 的那個數(shù)組元素在賦值給 value 時都會被跳過幻赚,這就說不通了,那就應該在if(count==0) 里面改臊旭,改了又有bug!!

在網(wǎng)上找了兩篇博客落恼,這一思路的寫法都是那樣跳過的,但是驗證又有問題离熏,差點要放棄佳谦,找第三篇博客的時候, 看到別人還寫了驗證輸入數(shù)組是否存在數(shù)量超過長度一般的數(shù)的代碼滋戳,忽然發(fā)現(xiàn)自己之前自己設置的數(shù)組中重復數(shù)最高的數(shù)沒有超過數(shù)組長度的一半W昝铩!所以才會報錯胧瓜!于是把數(shù)組修正過來矢棚,網(wǎng)上的代碼就不報錯了!但是自己的代碼還是有錯府喳,正百思不得其解的時候忽然想到 value=arr[i--]; 這種寫法是先賦值蒲肋,i 再-1,修正為 [--i] 就沒問題了

擴展:加強版水王問題

問題

我們知道,水王問題:有N個數(shù)兜粘,其中有一個數(shù)出現(xiàn)超過一半申窘,要求在線性時間求出這個數(shù)。(就是上面解決的問題)

加強版水王:有N個數(shù)孔轴,其中有一個數(shù)剛好出現(xiàn)一半次數(shù)剃法,要求在線性時間內(nèi)求出這個數(shù)。

思路

仔細分析的話路鹰,占一半的數(shù)字贷洲,只能在兩個變量中出現(xiàn):value 和數(shù)組最后一個元素arr[arrLen-1]。只需要在遍歷數(shù)組的時候統(tǒng)計最后一個變量arr[arrLen-1] 的出現(xiàn)次數(shù)即可晋柱,如果=arrLen/2 优构,則它就是要找的元素,否則 value 就是

代碼

int findK(int* arr,int arrLen){
    int value=arr[0];
    int count=1;
    int countOfLast=0;//統(tǒng)計最后的元素arr[n-1]出現(xiàn)的個數(shù) 
        
    for(int i=1;i<arrLen;i++){
        
        //增加最后一個元素的計數(shù)步驟
        if(arr[i]==arr[arrLen-1]) 
            countOfLast++;
        
        if(count==0){
            i--;//避免value的賦值跳過那個使count等于0的與value比較的數(shù)組元素 
            value=arr[i];
            count++;
        }

        else{
            if(value==arr[i])//count!=0 && value==arr[i] 
                count++;
            else//count!=0&value!=arr[i]
                count--;
        }
    }
    
    //增加最后一個元素的計數(shù)步驟
    if(arr[0]=arr[arrLen-1])
        countOfLast++;
    //如果最后一個元素出現(xiàn)次數(shù)是n/2,則這個元素就是要找的數(shù) 
    if(countOfLast==arrLen/2)
        return arr[arrLen-1];
    else
        return value;
}

參考資料

[1] 一個數(shù)組中有一個數(shù)字的次數(shù)超過了數(shù)組的一半

[2] 加強版水王:找出出現(xiàn)次數(shù)剛好是一半的數(shù)字

l

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末雁竞,一起剝皮案震驚了整個濱河市钦椭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌碑诉,老刑警劉巖彪腔,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異进栽,居然都是意外死亡德挣,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進店門泪幌,熙熙樓的掌柜王于貴愁眉苦臉地迎上來盲厌,“玉大人,你說我怎么就攤上這事祸泪。” “怎么了建芙?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵没隘,是天一觀的道長。 經(jīng)常有香客問我禁荸,道長右蒲,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任赶熟,我火速辦了婚禮瑰妄,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘映砖。我一直安慰自己间坐,他們只是感情好,可當我...
    茶點故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竹宋,像睡著了一般劳澄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蜈七,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天秒拔,我揣著相機與錄音,去河邊找鬼飒硅。 笑死砂缩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的三娩。 我是一名探鬼主播梯轻,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼尽棕!你這毒婦竟也來了喳挑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤滔悉,失蹤者是張志新(化名)和其女友劉穎伊诵,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體回官,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡曹宴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了歉提。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笛坦。...
    茶點故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖苔巨,靈堂內(nèi)的尸體忽然破棺而出版扩,到底是詐尸還是另有隱情,我是刑警寧澤侄泽,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布礁芦,位于F島的核電站,受9級特大地震影響悼尾,放射性物質(zhì)發(fā)生泄漏柿扣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一闺魏、第九天 我趴在偏房一處隱蔽的房頂上張望未状。 院中可真熱鬧,春花似錦析桥、人聲如沸司草。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽翻伺。三九已至材泄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吨岭,已是汗流浹背拉宗。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留辣辫,地道東北人旦事。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像急灭,于是被迫代替她去往敵國和親姐浮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,678評論 2 354

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

  • Lua 5.1 參考手冊 by Roberto Ierusalimschy, Luiz Henrique de F...
    蘇黎九歌閱讀 13,790評論 0 38
  • 《忠犬八公的故事》與《忠愛無言》這兩部影片都是講述狗狗與人類之間的真摯友誼葬馋,感動了很多人卖鲤。一個是秋田犬小八與...
    語文公子閱讀 296評論 0 2
  • 今天從武漢回鄭州,一下午陪著家人畴嘶,老婆和孩子都很高興蛋逾,孩子很喜歡思俊送的小兔子,兒子一直要陪著窗悯,理解他那種舍不...
    姚常春閱讀 133評論 1 5
  • 昨天背了一天的現(xiàn)代文學和外新史区匣,到了晚上累得不行,睡得早蒋院。 早睡引發(fā)早起亏钩。 好幾種鳥叫聲隔空呼應,聽見了久違的雞鳴...
    HI聽海閱讀 238評論 0 0