查找字符串中霞玄,出現(xiàn)最先出現(xiàn)最多的字符

查找字符串中焕毫,出現(xiàn)最先出現(xiàn)最多的字符

查找字符串中最先出現(xiàn)次數(shù)最多的字符沛善。首先需要查找出現(xiàn)次數(shù)最多的字符串航揉,然后查找最多的字符串中出現(xiàn)最早的哪一個(gè)字符。
分析:遍歷字符串即可統(tǒng)計(jì)到各個(gè)字符出現(xiàn)的次數(shù)金刁;統(tǒng)計(jì)最早且最多的字符時(shí)帅涂,一般有兩種思路:

  • 記錄各個(gè)字符出現(xiàn)的順序。找到出現(xiàn)最多的次數(shù)后尤蛮,結(jié)合字符出現(xiàn)的順序即可獲取到出現(xiàn)最早的字符媳友;
  • 逆序遍歷字符串。順序遍歷一邊不容易查找到最早出現(xiàn)的字符产捞,但是能夠找到最晚出現(xiàn)最多的字符醇锚。所以逆序遍歷字符串,找到最晚出現(xiàn)的字符坯临,那么就找到了最早出現(xiàn)最多次數(shù)的字符了焊唬。
    結(jié)合著兩種思路,一般有一下幾種方法實(shí)現(xiàn)看靠。
  1. 使用map赶促,遍歷兩邊。第一遍挟炬,遍歷字符串?dāng)?shù)組鸥滨, 統(tǒng)計(jì)各個(gè)字符出現(xiàn)的次數(shù),并記錄出現(xiàn)最多的次數(shù)N谤祖;第二遍婿滓,遍歷字符串,從map中獲取字符出現(xiàn)次數(shù)泊脐,找到第一個(gè)出現(xiàn)次數(shù)為N的字符空幻。
public static char cal2(String str) {
    Map<Character,Integer> map = new HashMap<>(MAX_CHAR_INT);
    char[] ch = str.toCharArray();
    for (int i = 0;i<ch.length;i++) {
        if(map.containsKey(ch[i])){
            map.put(ch[i],map.get(ch[i])+1);
        }else {
            map.put(ch[i],1);
        }
    }
    int index = -1 ;
    char maxChar = ch[0];
    for(int i = 0 ;i<ch.length;i++){
        if(map.get(ch[i]) > index ){
            index = map.get(ch[i]);
            maxChar = ch[i] ;
        }
    }
    return maxChar;
}
  1. 使用map,逆序遍歷一次容客。逆序遍歷字符數(shù)組秕铛,記錄出現(xiàn)次數(shù)最多的字符C和最多次數(shù)N,由于是逆序遍歷缩挑,最后記錄到的字符就是最早出現(xiàn)且出現(xiàn)次數(shù)最多的字符但两。

public static char cal3(String str) {
    Map<Character,Integer> map = new HashMap<>(MAX_CHAR_INT);
    char[] ch = str.toCharArray();
    int max = 0 ;
    char res = ch[0] ;
    for (int i = ch.length -1 ; i >= 0;i --) {
        if(map.containsKey(ch[i])){
            map.put(ch[i],map.get(ch[i])+1);
            if(map.get(ch[i]) >= max ){
                max = map.get(ch[i]);
                res = ch[i] ;
            }
        }else {
            map.put(ch[i],1);
        }
    }
    return res ;
}
  1. 使用數(shù)組。首先字符的個(gè)數(shù)是有限的(Character.MAX_VALUE-1個(gè))供置,可以使用數(shù)組谨湘,使數(shù)組的每個(gè)下標(biāo)對(duì)應(yīng)一個(gè)字符(char和int可以相互抓換),基于這一點(diǎn)可以使用數(shù)組nums來(lái)記錄各個(gè)字符出現(xiàn)的次數(shù),使用orders數(shù)組記錄各個(gè)字符出現(xiàn)的順序(字符出現(xiàn)次數(shù)為0時(shí)表示第一次出現(xiàn)紧阔,此時(shí)將該字符記錄在orders數(shù)組最后)坊罢。
    執(zhí)行步驟:
  • 記錄各字符出現(xiàn)次數(shù)及出現(xiàn)順序:通過(guò)一次遍歷即可獲取到所有字符出現(xiàn)的次數(shù)及順序(效率O(n));
  • 查找出現(xiàn)最多的字符:通過(guò)一次對(duì)nums表的遍歷就能找到最多值max擅耽,同時(shí)記錄對(duì)應(yīng)的下標(biāo)(效率為固定值(Character.MAX_VALUE-1))活孩;
  • 查找出現(xiàn)最早且最多的字符:檢驗(yàn)是否有多個(gè)出現(xiàn)次數(shù)最多的字符(如a/b都出現(xiàn)了100次),找到在orders表里出現(xiàn)最早的乖仇。從第二步中的下標(biāo)開始遍歷nums憾儒,找到出現(xiàn)次數(shù)為max的下標(biāo),遍歷ordres找到其出現(xiàn)順序(記錄最小下標(biāo)值)乃沙。當(dāng)nums遍歷完成后起趾,記錄到的orders最小下標(biāo)即出現(xiàn)最早的字符。此過(guò)程效率最優(yōu)為1警儒,此時(shí)int值最大的字符出現(xiàn)次數(shù)最多的字符训裆,且第一個(gè)出現(xiàn);效率最差為log2(n)蜀铲,此時(shí)所有字符出現(xiàn)次數(shù)均相同缭保。
 public static Character findFirstMaxChar(@NonNull String str){
        int indx = 0;
        char[] orders = new char[MAX_CHAR_INT];
        int[] nums = new int[MAX_CHAR_INT];
        for(int i = 0, len = str.length(); i < len; i ++){
            char c = str.charAt(i);
            if(nums[c] > 0){
                nums[c] = nums[c] + 1;
            } else {
                nums[c] = 1;
                orders[indx ++] = c;
            }
        }
        //find max num
        int max = 0, maxIndx = 0;
        for (int i = 0; i < nums.length; i++) {
            if( max < nums[i] ){
                max = nums[i];
                maxIndx = i;
            }
        }
        // find first max num char
        int minIndx = orders.length-1;
        for(int i = maxIndx; i < nums.length; i ++){
            if(nums[i] < max){
                continue;
            }
            for (int j = 0; j < minIndx; j++) {
                if( i != (int) orders[j]){
                    continue;
                }
                if(minIndx > j){
                    minIndx = j;
                }
                break;
            }
        }
//        System.out.println(String.format("最先出現(xiàn)最多的字符是:'%c',出現(xiàn)次數(shù):%d", orders[minIndx], max));
        return orders[minIndx];
    }
  1. 基于第二種方法的思想蝙茶,對(duì)第三種方法優(yōu)化艺骂。對(duì)字符串倒序遍歷,遍歷一次隆夯,記錄各個(gè)字符出現(xiàn)次數(shù)钳恕,并記錄最大出現(xiàn)次數(shù),及最大次數(shù)是的下標(biāo)蹄衷。由于是從后往前遍歷忧额,記錄到最后一個(gè)出現(xiàn)最多次數(shù)的字符就是最早出現(xiàn)且出現(xiàn)最多的字符。須注意一點(diǎn)愧口,須判斷當(dāng)前字符出現(xiàn)次數(shù)大于等于最多次數(shù)時(shí)睦番,更新最多次數(shù)字符及下標(biāo)時(shí)。
public static Character findFirstMaxChar0(@NonNull String str){
        int[] nums = new int[MAX_CHAR_INT];
        int maxN = 0;
        char maxC = str.charAt(0);
        for(int i = str.length() - 1; i >= 0; i --){
            char c = str.charAt(i);
            if(nums[c] > 0){
                nums[c] = nums[c] + 1;
            } else {
                nums[c] = 1;
            }
            if(nums[c] >= maxN){
                maxN = nums[c];
                maxC = c;
            }
        }
//        System.out.println(String.format("最先出現(xiàn)最多的字符是:'%c'耍属,出現(xiàn)次數(shù):%d", maxC, maxN));
        return maxC;
    }

各個(gè)方法運(yùn)行100次的平均運(yùn)行時(shí)間對(duì)比如下圖所示托嚣。

N表示字符串長(zhǎng)度,一下時(shí)間都是每個(gè)方法運(yùn)行100次得到的平均時(shí)間厚骗,單位毫秒


兩種使用數(shù)組的方法運(yùn)行時(shí)間對(duì)比
四種方法運(yùn)行時(shí)間對(duì)比

結(jié)論:

  • 使用map的記錄字符出現(xiàn)次數(shù)的方法運(yùn)行效率都不高示启,究其原因,程序中使用了注入“containsKey”领舰、“get”夫嗓、”put“等方法迟螺,乍一看代碼只有一行,實(shí)際這些方法內(nèi)部運(yùn)行了很多其他代碼舍咖,如hash矩父,遍歷entry數(shù)組,遍歷鏈表等行為排霉。這些方法內(nèi)部增加的運(yùn)行時(shí)間復(fù)雜度沒(méi)有被計(jì)算在內(nèi)浙垫,因此看上去很簡(jiǎn)潔的代碼實(shí)際運(yùn)行效率并不高;不過(guò)從第一個(gè)方法到第二個(gè)方法的優(yōu)化還是值得肯定的郑诺;
  • 使用數(shù)組記錄字符出現(xiàn)次數(shù)的方法效率高,其原因是判斷字符第一次出現(xiàn)杉武,及獲取字符出現(xiàn)次數(shù)的操作都是直接訪問(wèn)數(shù)組指定下標(biāo)辙诞,沒(méi)有其他的附帶操作成本;
  • 從第三種方法到第四種方法的優(yōu)化轻抱,實(shí)際上只優(yōu)化了程序的可讀性飞涂,并沒(méi)有減少程序的運(yùn)行時(shí)間。因?yàn)槌绦蜃钕臅r(shí)間的部分是第一步獲取字符出現(xiàn)次數(shù)及順序上祈搜,優(yōu)化后的方法恰好是在這一步增加了操作较店,原本只有對(duì)數(shù)組的一次讀取,一次比較和一次賦值操作容燕,優(yōu)化后卻變成了對(duì)數(shù)組的一次讀取梁呈、兩次比較、一次賦值蘸秘。隨著數(shù)據(jù)量的增加多一次比較所造成的時(shí)間成本便凸顯了出來(lái)官卡,因此優(yōu)化后的程序并沒(méi)有優(yōu)化前運(yùn)行效率高,但可讀性卻明顯高于優(yōu)化前醋虏。在時(shí)間成本并沒(méi)有量級(jí)差別時(shí)寻咒,更應(yīng)考慮程序的可讀性。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颈嚼,一起剝皮案震驚了整個(gè)濱河市毛秘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌阻课,老刑警劉巖叫挟,帶你破解...
    沈念sama閱讀 221,635評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異限煞,居然都是意外死亡霞揉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門晰骑,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)适秩,“玉大人绊序,你說(shuō)我怎么就攤上這事』嘬瘢” “怎么了骤公?”我有些...
    開封第一講書人閱讀 168,083評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)扬跋。 經(jīng)常有香客問(wèn)我阶捆,道長(zhǎng),這世上最難降的妖魔是什么钦听? 我笑而不...
    開封第一講書人閱讀 59,640評(píng)論 1 296
  • 正文 為了忘掉前任洒试,我火速辦了婚禮,結(jié)果婚禮上朴上,老公的妹妹穿的比我還像新娘垒棋。我一直安慰自己,他們只是感情好痪宰,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,640評(píng)論 6 397
  • 文/花漫 我一把揭開白布叼架。 她就那樣靜靜地躺著,像睡著了一般衣撬。 火紅的嫁衣襯著肌膚如雪乖订。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評(píng)論 1 308
  • 那天具练,我揣著相機(jī)與錄音乍构,去河邊找鬼。 笑死扛点,一個(gè)胖子當(dāng)著我的面吹牛蜡吧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播占键,決...
    沈念sama閱讀 40,833評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼昔善,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了畔乙?” 一聲冷哼從身側(cè)響起君仆,我...
    開封第一講書人閱讀 39,736評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎牲距,沒(méi)想到半個(gè)月后返咱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牍鞠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,369評(píng)論 3 340
  • 正文 我和宋清朗相戀三年咖摹,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片难述。...
    茶點(diǎn)故事閱讀 40,503評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡萤晴,死狀恐怖吐句,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情店读,我是刑警寧澤嗦枢,帶...
    沈念sama閱讀 36,185評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站屯断,受9級(jí)特大地震影響文虏,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜殖演,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,870評(píng)論 3 333
  • 文/蒙蒙 一氧秘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧趴久,春花似錦丸相、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)妥箕。三九已至滥酥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間畦幢,已是汗流浹背坎吻。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留宇葱,地道東北人瘦真。 一個(gè)月前我還...
    沈念sama閱讀 48,909評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像黍瞧,于是被迫代替她去往敵國(guó)和親诸尽。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,512評(píng)論 2 359

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

  • 第5章 引用類型(返回首頁(yè)) 本章內(nèi)容 使用對(duì)象 創(chuàng)建并操作數(shù)組 理解基本的JavaScript類型 使用基本類型...
    大學(xué)一百閱讀 3,238評(píng)論 0 4
  • 前言 最先接觸編程的知識(shí)是在大學(xué)里面,大學(xué)里面學(xué)了一些基礎(chǔ)的知識(shí)年局,c語(yǔ)言际看,java語(yǔ)言,單片機(jī)的匯編語(yǔ)言等矢否;大學(xué)畢...
    oceanfive閱讀 3,095評(píng)論 0 7
  • 概要 64學(xué)時(shí) 3.5學(xué)分 章節(jié)安排 電子商務(wù)網(wǎng)站概況 HTML5+CSS3 JavaScript Node 電子...
    阿啊阿吖丁閱讀 9,223評(píng)論 0 3
  • 悲觀這種東西 樂(lè)天派難以理解 有時(shí)候 就像臉上那塊胎記 空氣里傳來(lái)戲謔之聲 像是一種恥辱 仿佛就是與生俱來(lái) 像毒刺...
    faa101ab89b1閱讀 249評(píng)論 0 0
  • 晚上好像快三點(diǎn)入睡僵朗,早上九點(diǎn)半起床赖欣,這幾天好像形成規(guī)律了屑彻。起來(lái)出去買了一個(gè)雜糧煎餅和搟面皮,小姨帶孩子來(lái)我家了畏鼓。...
    蒼涼是妳閱讀 202評(píng)論 0 0