去除重复字母

题目:去除重复字母(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 -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

你可能感兴趣的:(去除重复字母)