數(shù)組中計算某個元素出現(xiàn)次數(shù)的問題

我這篇文章要講的一道算法題憨愉,一點都不難兼吓,可以說是小白級別的臂港,是關(guān)于一個數(shù)組中計算某個元素的重復(fù)個數(shù)的問題。

具體問題:看如下一個無序的數(shù)組,求其中數(shù)字2出現(xiàn)的次數(shù)审孽。怎么樣县袱,是不是超級簡單:)

[0,2,1,1,2,3,5,2,3,3,4,5,7,6,2]

能夠想到的解法,直接一趟for循環(huán)佑力,碰到元素等于2了就開始計數(shù)加一式散,2的個數(shù)就是計數(shù)值。

挺好打颤。這肯定能解決問題暴拄。

下面給出上面思路的實現(xiàn),使用c++代碼编饺。值得注意的是乖篷,這里應(yīng)該使用c++中的模板,也就是通常說的泛型透且。因為那伐,我們并不確定給定數(shù)組元素的具體類型,除了上面給出的數(shù)組元素是整數(shù)外石蔗,也可能是字符串,或者自定義對象畅形。

template <typename T>
int countOccurrences(vector<T> arr, T target){
    
    int result = 0;
    for (int i = 0; i < arr.size(); i++) {
        if (target == arr[i]) {
            result++;
        }
    }
    
    return result;
}

還有沒有其他方法呢养距?這個時候就可以想一下,對了日熬,我們也可以使用查找表來解決這個問題棍厌,以元素值為鍵,值為數(shù)組中相同元素的個數(shù)竖席。需要一趟for 循環(huán)來統(tǒng)計相同元素的個數(shù)耘纱,最后返回這個查找表中對應(yīng)元素的值就好了。

給出代碼:

template <typename T>
int countOccurrences(vector<T> arr, T target){
    
    unordered_map<T, int> map;
    for (int i = 0; i < arr.size(); i++) {
        map[arr[i]]++;
    }
    
    return map[target];
}

想一想毕荐,如果這個數(shù)組變成有序了束析?可以想到其他方法來解決這個問題嗎?

[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]

此時就可以使用二分查找了憎亚,二分查找主要解決的就是有序集合的查找問題员寇。可是問題來了第美,這里有4個2蝶锋,二分查找只能找到其中的一個2,這....好像使用二分查找也不行吧什往。

如果有這個疑問扳缕,可以先按照二分查找的思路,停下來先思考下如何使用二分查找來解決這個問題。

繼續(xù)躯舔。

其實驴剔,我們可以使用二次二分查找,第一次尋找的是查找值的左邊界庸毫,第二次尋找的是查找值的右邊界仔拟。

先給出代碼,然后根據(jù)代碼進行講解飒赃。

template <typename T>
int countOccurrences(vector<T> arr, T target){
    
    int low_left = 0;
    int high_left = arr.size();
    
    while (low_left < high_left) {
        int middle = low_left + (high_left - low_left) / 2;
        if (arr[middle] < target) {
            low_left = middle + 1;
        } else {
            high_left = middle;
        }
    }
    
    int low_right = 0;
    int high_right = arr.size();
    
    while (low_right < high_right) {
        int middle = low_right + (high_right - low_right) / 2;
        if (arr[middle] > target) {
            high_right = middle;
        } else {
            low_right = middle  + 1;
        }
    }
    
    return low_right - low_left;
}

我準備根據(jù)程序運行的邏輯利花,一步步進行講解。

首先载佳,這是我們傳入的數(shù)組炒事,尋找2的重復(fù)元素

vector<int> vec = vector<int>{0,1,1,2,2,2,2,3,3,3,4,5,5,6,7};
int result = countOccurrences(vec, 2);

第一個循環(huán)的作用是尋找左邊界,也就是2起始的索引蔫慧,在第一個while循環(huán)前挠乳,設(shè)置兩個變量,low_left,high_left,我對這兩個值的定義是在區(qū)間 [low_left,high_left) 中尋找目標值姑躲,注意區(qū)間是前閉后開的,所以這兩個值的初始值設(shè)置為 low_left = 0,high_left = arr.size()睡扬。

經(jīng)過第一個循環(huán),中間值middle = 7黍析,arr[7] = 3, 3大于2卖怜,所以此時 high_right = 7,數(shù)組如下所示阐枣,high_left此時指向3马靠。為了便于查看,#號表示low_left的位置蔼两,*號表示high_left的位置甩鳄。

[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
 #             *

繼續(xù)第二次循環(huán),中間值middle = 3,arr[3] = 2,2等于目標值额划,所以此時high_left = 3,所以在這里也可以看出這里用到的二分查找與一般的二分查找的區(qū)別了妙啃,一般的二分查找在找到目標值后就會結(jié)束循環(huán),這里卻不然俊戳,會繼續(xù)向左邊部分查找彬祖。因為我們要找的是2第一次出現(xiàn)的位置。

[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
 #     *

繼續(xù)第三次循環(huán)品抽,中間值middle = 1,arr[1] = 1,1小于2储笑,所以此時low_left = middle + 1,就應(yīng)該等于2。

[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
     # *

繼續(xù)第四次循環(huán)圆恤,middle = 2 + (3 - 2) / 2 = 2, arr[2] = 1, 1小于2突倍,所以此時low_left繼續(xù)加一腔稀,low_left = 3,結(jié)束循環(huán)。這個時候羽历,我們就找到了2第一次出現(xiàn)的位置焊虏,如圖。

[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
       #
       *

尋找右邊界與左邊的邏輯類似秕磷,給出圖示诵闭,就不一一講解了,與尋找左邊界不同的是澎嚣,在找到2之后疏尿,會繼續(xù)向右查找,2結(jié)束的位置易桃。

[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
 #             *
 
[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
         #     *
         
[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
           #   *
           
[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
             # *
             
[0,1,1,2,2,2,2,3,3,3,4,5,5,6,7]
               #
               *

查找到的結(jié)果右邊界是索引在7的位置褥琐,所以2出現(xiàn)的次數(shù)是右邊界減去左邊界,也就是7減去3等于4晤郑,求出結(jié)果敌呈。

接下來討論一種特殊情況。

當(dāng)前數(shù)組中不包括需要查找的元素造寝。那么此時low_right 和 low_left 會返回相同的數(shù)磕洪,兩數(shù)相減等于零,是滿足的诫龙,

總結(jié)一下褐鸥,在這個方法中,查找到值后赐稽,并不會停止查找,而是繼續(xù)向左或向右浑侥,找到目標值的起始位置和結(jié)束位置姊舵。可以看到寓落,在掌握基本知識的基礎(chǔ)上括丁,能靈活運用是非常重要的。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伶选,一起剝皮案震驚了整個濱河市史飞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仰税,老刑警劉巖构资,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異陨簇,居然都是意外死亡吐绵,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來己单,“玉大人唉窃,你說我怎么就攤上這事∥屏” “怎么了纹份?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長廷痘。 經(jīng)常有香客問我蔓涧,道長,這世上最難降的妖魔是什么牍疏? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任蠢笋,我火速辦了婚禮,結(jié)果婚禮上鳞陨,老公的妹妹穿的比我還像新娘昨寞。我一直安慰自己,他們只是感情好厦滤,可當(dāng)我...
    茶點故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布援岩。 她就那樣靜靜地躺著,像睡著了一般掏导。 火紅的嫁衣襯著肌膚如雪享怀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天趟咆,我揣著相機與錄音添瓷,去河邊找鬼。 笑死值纱,一個胖子當(dāng)著我的面吹牛鳞贷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播虐唠,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼搀愧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了疆偿?” 一聲冷哼從身側(cè)響起咱筛,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎杆故,沒想到半個月后迅箩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨居荒郊野嶺守林人離奇死亡处铛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年沙热,在試婚紗的時候發(fā)現(xiàn)自己被綠了叉钥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡篙贸,死狀恐怖投队,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情爵川,我是刑警寧澤敷鸦,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站寝贡,受9級特大地震影響扒披,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜圃泡,卻給世界環(huán)境...
    茶點故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一碟案、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颇蜡,春花似錦价说、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至缤弦,卻和暖如春领迈,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碍沐。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工狸捅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人累提。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓尘喝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親刻恭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,044評論 2 355

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