算法—去除重復(fù)字母

給你一個僅包含小寫字母的字符串扎筒,請你去除字符串中重復(fù)的字母,使得每個字母只出現(xiàn)一次酬姆。需保證返回結(jié)果的字典序最惺茸馈(要求不能打亂其他字符的相對位置)。
示例1: 輸入:"bcabc"辞色, 輸出:"abc"
示例2: 輸入:"cbacdcbc"症脂, 輸出:"acdb"

字典序: 字符串之間比較和數(shù)字比較不一樣; 字符串比較是從頭往后挨個字符比較,那個字符串大取決于兩個字符串中第一個對應(yīng)不相等的字符; 例如 任意一個a開頭的字符串都大于任意一個b開頭的字符串;例如字典中apple 大于 book;
題目的意思,你去除重復(fù)字母后,需要按最小的字典序返回.并且不能打亂其他字母的相對位置;
例如 bcabc 你應(yīng)該返回abc, 而不是bca,cab;
例如 cbacdcbc 應(yīng)該返回acdb,而不是cbad,bacd,adcb
例如 zab,應(yīng)該返回zab,而不是abz;

思路:

  1. 判斷字符串可能出現(xiàn)的特殊情況
  2. 用一個record數(shù)組記錄字符串中字母出現(xiàn)的次數(shù);
  3. 申請一個字符串棧stack用來存儲去除重復(fù)字母的結(jié)果,并利用它的特性幫助我們找到正確的次序;
  4. 遍歷字符串s
  5. 從0~top,遍歷stack 判斷當(dāng)前字符s[i]是否存在于棧stack中
    如果當(dāng)前字符是否存在于棧的定義一個falg 標(biāo)記isExist, 0表示不存在, 1表示存在
    6.如果isExist存在,record[s[i]]位置上的出現(xiàn)次數(shù)減一,并繼續(xù)遍歷下一個字符; 表示當(dāng)前的stack已經(jīng)有這個字符了沒有必要處理這個重復(fù)的字母;
    7.如果isExist不存在,則
    如果不存在,則需要循環(huán)一個找到一個正確的位置,然后在存儲起來;
    如果不存在淫僻,跳過棧中所有比當(dāng)前字符大诱篷、且后面還會出現(xiàn)的元素,然后將當(dāng)前字符入棧
    top > -1表示棧非空
    stack[top] > s[i]表示棧頂元素比當(dāng)前元素大
    record[stack[top]] > 1表示后面還會出現(xiàn)
    通過一個while循環(huán)找到將棧中位置錯誤的數(shù)據(jù),出棧. 找當(dāng)前合適的位置,則結(jié)束while循環(huán);
    找到合理的位置后,則將當(dāng)前字符s[i]入棧;

8.直到遍歷完所有字符后,則為字符串棧stack 添加一個結(jié)束符'\0',并返回當(dāng)前字符串首地址;

char *removeDuplicateLetters(char *s) {
    /*
     ① 特殊情況處理,s為空,或者字符串長度為0;
     ② 特殊情況,s的長度為1,則沒有必要后續(xù)的處理,則直接返回s;
     */
   int len = (int)strlen(s);
    if (len < 1) {
        return "have no string";
    }
    
    if (len == 1) {
        return s;
    }
    
  
    char record[26] = {0};  //record數(shù)組,用來記錄字符串s中每個字符未來會出現(xiàn)的次數(shù);
    
    //申請一個字符串stack;(用棧的特性來進行stack字符串的數(shù)據(jù)進出)
    char* stack = (char*)malloc((len+1)  * sizeof(char));
    //memset(void *s, int ch, size_t n) 將stack(len+1) *sizeof(char)長度范圍的空間填充0;
    memset(stack, 0, (len+1) * sizeof(char));
    //stack 棧頂賦初值為-1;
    int top = -1;
    
     int i;
    for (i = 0; i < len; i++) { //1.統(tǒng)計每個字符的頻次
        record[s[i] - 'a']++;
    }
    
    //2.遍歷s,入棧
    for (i = 0; i < len; i++) {        
        //isExist 標(biāo)記, 判斷當(dāng)前字符是否存在棧中;
        int isExist = 0;
        
        //①從0~top,遍歷stack 判斷當(dāng)前字符s[i]是否存在于棧stack中
        //如果當(dāng)前字符是否存在于棧的flag, 0表示不存在, 1表示存在
        //top指向棧頂(也是執(zhí)行stack字符串最后一個字符的位置,表示字符串長度上限)
        for (int j = 0; j <= top; j++) {
            if (s[i] == stack[j]) {
                isExist = 1;
                break;
            }
        }
        
        //② 如果存在,record[s[i]]位置上的出現(xiàn)次數(shù)減一雳灵,并繼續(xù)遍歷下一個字符
        //③ 如果不存在,則需要循環(huán)一個正確位置存儲起來;
        //④ 如果不存在棕所,跳過棧中所有比當(dāng)前字符大、且后面還會出現(xiàn)的元素悯辙,然后將當(dāng)前字符入棧
        // top > -1表示棧非空
        //stack[top] > s[i]表示棧頂元素比當(dāng)前元素大
        //record[stack[top]] > 1表示后面還會出現(xiàn)
        //例如b,c因為不符合以下條件會直接入棧.stack[] = "bc",但是當(dāng)當(dāng)前字符是"a"時,由于bcabc,a不應(yīng)該是在stack的順序是"bca",所以要把位置不符合的字符出棧;
        //top = 1,stack[top] > s[i], c>a; 并且stack[top] 在之后還會重復(fù)的出現(xiàn),所以我們可以安心的把stack中的棧頂C出棧,所以stack[]="b",top減一后等于0; 同時也需要將record[c]出現(xiàn)次數(shù)減一;
        //top=0,stack[top]>s[i],b>a,并且stack[top] 在之后還會出現(xiàn),所以stack把棧頂b出棧,所以此時棧stack[]="",top減一后等于-1, 此時棧中位置不正確的字符都已經(jīng)移除;
        
        if (isExist == 1) {
            record[s[i] - 'a']--;
        } else {
            while (top > -1 && stack[top] > s[i] && record[stack[top] - 'a'] > 1) {
               
                // 跳過該元素琳省,頻次要減一
                record[stack[top] - 'a']--;
                // 出棧
                top--;
            }
            
            //⑤ 結(jié)束while 循環(huán);
            //循環(huán)結(jié)束的3種可能性:(1)移動到棧底(top == -1) ; (2)棧頂元素小于當(dāng)前元素(stack[top] <= s[i]) (3)棧頂元素后面不出現(xiàn)(record[stack[top]] == 1)
            // 此時,當(dāng)前元素要插入到top的下一個位置
            // top往上移動1位
            top++;
            // 入棧
            stack[top] = s[i];
        }
    }
    
    //結(jié)束棧頂添加字符結(jié)束符
    stack[++top] = '\0';
    
    return stack;
}
int main(int argc, const char * argv[]) {
    // insert code here...
    printf("去掉重復(fù)字母! LeetCode-困難 \n");
    
    char *s ;
    s = removeDuplicateLetters("bcabc");
    printf("%s\n",s);//abc
 
    s = removeDuplicateLetters("zab");
    printf("%s\n",s);//zab

    s = removeDuplicateLetters("cbacdcbc");
    printf("%s\n",s);//acdb
    
    printf("\n");
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末躲撰,一起剝皮案震驚了整個濱河市针贬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拢蛋,老刑警劉巖桦他,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谆棱,居然都是意外死亡快压,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門垃瞧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蔫劣,“玉大人,你說我怎么就攤上這事个从÷龃保” “怎么了歪沃?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長嫌松。 經(jīng)常有香客問我沪曙,道長,這世上最難降的妖魔是什么豆瘫? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮菊值,結(jié)果婚禮上外驱,老公的妹妹穿的比我還像新娘。我一直安慰自己腻窒,他們只是感情好昵宇,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著儿子,像睡著了一般瓦哎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上柔逼,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天蒋譬,我揣著相機與錄音,去河邊找鬼愉适。 笑死犯助,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的维咸。 我是一名探鬼主播剂买,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼癌蓖!你這毒婦竟也來了瞬哼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤租副,失蹤者是張志新(化名)和其女友劉穎坐慰,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體用僧,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡讨越,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了永毅。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片把跨。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖沼死,靈堂內(nèi)的尸體忽然破棺而出着逐,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布耸别,位于F島的核電站健芭,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏秀姐。R本人自食惡果不足惜慈迈,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望省有。 院中可真熱鬧痒留,春花似錦、人聲如沸蠢沿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽舷蟀。三九已至恤磷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間野宜,已是汗流浹背扫步。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留匈子,地道東北人锌妻。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像旬牲,于是被迫代替她去往敵國和親仿粹。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

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