去除重复字母

题目:去除重复字母(LeetCode-困难)
给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)

我们先来解释一下字典序最小是什么意思。
字典序最小,就是从头向后比,若前面的字符比后面的字符大,而且比较小的字符后面还存在与之前比较大的字符串相同,那么我们可以将前面比较大的字符移除,顺序选择从字符较小的开始排序,当前面字符比后面的字符大,而且较大的字符只出现了一次,那么他们之间的顺序不能改变,且不能打乱其他字母顺序的相对位置。
例如 bcabc 你应该返回abc, 而不是bca,cab;
例如 cbacdcbc 应该返回acdb,而不是cbad,bacd,adcb
例如 zab,应该返回zab,而不是abz;

解题思路:
1、首先判断字符串可能出现的特殊情况
2、用一个数组record记录字符串中每个字符出现的次数
3、创建一个字符串栈,用来存储去重复字母的结果
4、遍历字符串s
5、从0-top,遍历stack,判断当前字符s[i]是否存在栈中,如果存在,则用一个变量标记他
6、判断变量是否存在,存在的话,将record数组中相应的字母数-1,并继续遍历下一个字符。
7、如果不存在,则需要找一个正确的位置,存储起来
如果不存在,跳过栈中所有比当前字符大、且后面还会出现的元素,然后将当前字符入栈
top > -1表示栈非空
stack[top] > s[i]表示栈顶元素比当前元素大
record[stack[top]] > 1表示后面还会出现
通过一个while循环找到将栈中位置错误的数据,出栈. 找当前合适的位置,则结束while循环;
找到合理的位置后,则将当前字符s[i]入栈;

8.直到遍历完所有字符后,则为字符串栈stack 添加一个结束符'\0',并返回当前字符串首地址;

这一题最核心的地方在于,当发现后一个字符小于前面的字符,这里需要判断前面的字符出现的次数是否只有一次,若只有一次,则不做处理,若不止一次,则需要先将前面的字符出栈,将较小的字符入栈。
而在前面的record数组中,已经将每个字符出现的次数已经记录下来,并且在之前还会进行重复值判断。发现重复,将record中对应位置数-1。
具体细节操作,请看代码:

char *removedUplicateletter(char *s){
    //首先判断数组内是否有数据
    if(strlen(s) <=1){
        return s;
    }
    //新建一个数组,记录26个字母出现次数
    char record[26] = {0};
    int len = (int)strlen(s);
    
    //申请一个字符串栈Stack
    char *stack = (char *)malloc(sizeof(char)*(len+1));
    //将stack栈的内容全部填充为0
    memset(stack, 0, (len+1)*sizeof(char));
    //栈顶赋初值
    int top = -1;
    
    //1、统计每个字符出现的频次
    for (int i = 0; i<len; i++) {
        record[s[i]-'a'] ++;
    }
    //2、遍历s,入栈
    for (int i = 0; i<len; i++) {
        //记录栈中是否存在当前字符
        int exist = 0;
        /*
         1、从0-top开始遍历,遍历stack,判断当前字符s[i]是否存在于栈中
         2、如果存在,将exist赋值为1,
         3、top指向栈顶
        */
        for (int j = 0; j<=top; j++) {
            if(s[i] == stack[j]){
                exist = 1;
                break;;
            }
        }
        //2、 如果存在,record[s[i]]位置上的出现次数减一,并继续遍历下一个字符
        //3、 如果不存在,则需要循环一个正确位置存储起来;
        //4、 如果不存在,跳过栈中所有比当前字符大、且后面还会出现的元素,然后将当前字符入栈
        // top > -1表示栈非空
        //stack[top] > s[i]表示栈顶元素比当前元素大
        //record[stack[top]] > 1表示后面还会出现
        //例如b,c因为不符合以下条件会直接入栈.stack[] = "bc",但是当当前字符是"a"时,由于bcabc,a不应该是在stack的顺序是"bca",所以要把位置不符合的字符出栈;
        //top = 1,stack[top] > s[i], c>a; 并且stack[top] 在之后还会重复的出现,所以我们可以安心的把stack中的栈顶C出栈,所以stack[]="b",top减一后等于0; 同时也需要将record[c]出现次数减一;
        //top=0,stack[top]>s[i],b>a,并且stack[top] 在之后还会出现,所以stack把栈顶b出栈,所以此时栈stack[]="",top减一后等于-1, 此时栈中位置不正确的字符都已经移除;
        if(exist == 1){
            record[s[i]-'a']--;
        }else{
            while (top>-1 && s[top]>s[i] && record[stack[top]-'a']) {
                //记录当前字符串减一
                record[stack[top]-'a']--;
                //出栈
                top--;
            }
            //5、 结束while 循环;
            //循环结束的3种可能性:(1)移动到栈底(top == -1) ; (2)栈顶元素小于当前元素(stack[top] <= s[i]) (3)栈顶元素后面不出现(record[stack[top]] == 1)
            // 此时,当前元素要插入到top的下一个位置
            // top往上移动1位
            top++;
            stack[top] = s[i];
        }
    }
    stack[++top] = '\0';
    return stack;
}

打印结果:


15874381735288.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 题目链接难度:困难 类型: 贪心、栈 给定一个仅包含小写字母的字符串,去除字符串中重复的字母,...
    wzNote阅读 1,865评论 0 5
  • 题目 316. 去除重复字母 给定一个仅包含小写字母的字符串,去除字符串中重复的字母,使得每个字母只出现一次。需保...
    十月里的男艺术家阅读 466评论 0 0
  • 题目 给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最...
    _涼城阅读 259评论 0 1
  • 给定一个仅包含小写字母的字符串,去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不...
    vbuer阅读 795评论 0 0
  • 总有些这样的时候 /正是为了爱 才悄悄躲开 / 躲开的是身影 /躲不开的/却是那份/默默的情怀 月光下踯躅/睡梦里...
    亲爱的田田阅读 213评论 0 0