算法 | 如何用位運(yùn)算從一堆數(shù)中尋找出現(xiàn)K次的數(shù)庙睡?

前言
本文主要介紹如何使用位運(yùn)算從一堆數(shù)中尋找出現(xiàn)K次的數(shù),這一堆數(shù)中有很多數(shù)出現(xiàn)了M次技俐,只有一個(gè)數(shù)出現(xiàn)了K次乘陪,并且K是小于M的,另外要求額外空間復(fù)雜度為O(1)雕擂,時(shí)間復(fù)雜度為O(n)啡邑,那么該如何尋找出這個(gè)數(shù)呢?
例如井赌,給出一個(gè)數(shù)組arr=[1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4]谤逼,K = 2贵扰,M = 3。在這個(gè)數(shù)組中流部,只有1這個(gè)元素出現(xiàn)了2次戚绕,其他的元素都出現(xiàn)了3次,現(xiàn)在要求使用位運(yùn)算把1這個(gè)元素找出來(lái)枝冀。
思路分析
要求額外空間復(fù)雜度為O(1)舞丛,也就是說(shuō),我們只能創(chuàng)建有限的果漾、固定的幾個(gè)變量瓷马。
之前的幾個(gè)尋找元素的題目都用到了異或運(yùn)算來(lái)解決的,這個(gè)題目還能用異或運(yùn)算嗎跨晴?這個(gè)就不可以了欧聘,如果K是個(gè)偶數(shù)的話,用異或就直接給干廢了端盆。
我們知道怀骤,在Java中,int型的二進(jìn)制的長(zhǎng)度為32位焕妙。
如果把這個(gè)數(shù)組的所有元素都轉(zhuǎn)成二進(jìn)制蒋伦,然后把二進(jìn)制每個(gè)位置的數(shù)據(jù)相加,存放到一個(gè)長(zhǎng)度為32位的數(shù)組中呢焚鹊?
步驟
假如數(shù)組arr=[a,a,b,b,b,c,c,c,d,d,d]痕届,K = 2,M = 3末患,要找出a這個(gè)元素研叫。

先聲明一個(gè)32位長(zhǎng)度的數(shù)組tmp,里面的元素都默認(rèn)為0璧针。
循環(huán)遍歷數(shù)組嚷炉,并把數(shù)組中的每一個(gè)元素都轉(zhuǎn)為二進(jìn)制形式。
把每一個(gè)元素的二進(jìn)制的值都累加到第1步聲明的32位長(zhǎng)度的數(shù)組中探橱。
循環(huán)遍歷這個(gè)32位長(zhǎng)度的數(shù)組申屹,判斷數(shù)組中每個(gè)元素的數(shù)值和M的關(guān)系。
如果數(shù)組中的元素是M的整數(shù)倍隧膏,那么說(shuō)明這個(gè)位置是沒(méi)有a這個(gè)元素的哗讥。

循環(huán)arr數(shù)組過(guò)程如下:
第1個(gè)元素a的二進(jìn)制假設(shè)為01111,累加到tmp數(shù)組中為胞枕,01111杆煞。
第2個(gè)元素a的二進(jìn)制假設(shè)為01111,累加到tmp數(shù)組中為,02222索绪。
第3個(gè)元素b的二進(jìn)制假設(shè)為01000,累加到tmp數(shù)組中為贫悄,03222瑞驱。
第3個(gè)元素b的二進(jìn)制假設(shè)為01000,累加到tmp數(shù)組中為窄坦,04222唤反。
......
以此類(lèi)推,直到把所有的元素全部累加鸭津。
還原出現(xiàn)K次的數(shù)
tmp數(shù)組中的元素彤侍,假如為T(mén),代表著arr數(shù)組中元素二進(jìn)制位為1數(shù)出現(xiàn)的次數(shù)逆趋,他可能出現(xiàn)這幾種組合:

T = 1 * K + 1 * M盏阶,所有元素在這個(gè)二進(jìn)制位都為1。
T = 0 * K + 1 * M闻书,只有出現(xiàn)M次的數(shù)名斟,二進(jìn)制位為1。
T = 0 * K + 0 * M魄眉,所有元素在這個(gè)二進(jìn)制位都為0砰盐。
T = 1 * K + 0 * M,只有出現(xiàn)K次的數(shù)坑律,二進(jìn)制位為1岩梳。

從上面4種情況來(lái)看,因?yàn)?K < M晃择,如果說(shuō)T對(duì)M進(jìn)行取模運(yùn)算冀值,取模為0的話,說(shuō)明這個(gè)位置出現(xiàn)K次這個(gè)數(shù)的二進(jìn)制位一定為0宫屠,否則為1池摧。
所以,讓tmp數(shù)組中的元素與M進(jìn)行取模運(yùn)算激况,就能識(shí)別出來(lái)出現(xiàn)K次的數(shù)的二進(jìn)制位是什么情況作彤,然后把二進(jìn)制轉(zhuǎn)成十進(jìn)制就可以了,或者直接與0進(jìn)行或運(yùn)算乌逐,也能得到結(jié)果竭讳。
代碼實(shí)現(xiàn)
經(jīng)過(guò)上面的分析,來(lái)看下代碼是如何實(shí)現(xiàn)的吧浙踢。
public class Code18_FindKTimes {
public static int findKTimes(int[] arr, int k, int m) {
int[] tmp = new int[32];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j <= 31; j++) {
tmp[j] += (arr[i] >> j) & 1;
}
}
int res = 0;
for (int i = 0; i < 32; i++) {
if (tmp[i] % m != 0) {
res |= (1 << i);
}
}
return res;
}
public static void main(String[] args) {
int[] arr = {11, 11, 11, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4};
int kNum = findKTimes(arr, 3, 4);
System.out.println(kNum);
}
}
復(fù)制代碼
運(yùn)行輸出結(jié)果為:11绢慢。
(arr[i] >> j) & 1代碼含義為判斷arr[i]元素在第j位置的值是0還是1。
總結(jié)
本文主要介紹如何使用位運(yùn)算從一堆數(shù)中尋找出現(xiàn)K次的數(shù),利用了二進(jìn)制胰舆、或運(yùn)算骚露、以及題目中M次的邏輯關(guān)系。
如果你有更好的辦法缚窿,歡迎在評(píng)論區(qū)留言交流棘幸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市倦零,隨后出現(xiàn)的幾起案子误续,更是在濱河造成了極大的恐慌,老刑警劉巖扫茅,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蹋嵌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡葫隙,警方通過(guò)查閱死者的電腦和手機(jī)栽烂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)恋脚,“玉大人愕鼓,你說(shuō)我怎么就攤上這事』燮穑” “怎么了菇晃?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蚓挤。 經(jīng)常有香客問(wèn)我磺送,道長(zhǎng),這世上最難降的妖魔是什么灿意? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任估灿,我火速辦了婚禮,結(jié)果婚禮上缤剧,老公的妹妹穿的比我還像新娘馅袁。我一直安慰自己,他們只是感情好荒辕,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布汗销。 她就那樣靜靜地躺著,像睡著了一般抵窒。 火紅的嫁衣襯著肌膚如雪弛针。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,071評(píng)論 1 285
  • 那天李皇,我揣著相機(jī)與錄音削茁,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛茧跋,可吹牛的內(nèi)容都是我干的慰丛。 我是一名探鬼主播,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼瘾杭,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼诅病!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起富寿,我...
    開(kāi)封第一講書(shū)人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤睬隶,失蹤者是張志新(化名)和其女友劉穎锣夹,沒(méi)想到半個(gè)月后页徐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡银萍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年变勇,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贴唇。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡搀绣,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出戳气,到底是詐尸還是另有隱情链患,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布瓶您,位于F島的核電站麻捻,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏呀袱。R本人自食惡果不足惜贸毕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夜赵。 院中可真熱鬧明棍,春花似錦、人聲如沸寇僧。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)嘁傀。三九已至歌豺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間心包,已是汗流浹背类咧。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人痕惋。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓区宇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親值戳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子议谷,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

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