美文网首页
去除重复字母(LeetCode-困难)

去除重复字母(LeetCode-困难)

作者: 85ca4232089b | 来源:发表于2020-04-21 10:19 被阅读0次

demo
给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)
示例1:
输入:"bcabc"
输出:"abc"
示例2:
输入:"cbacdcbc"
输出:"acdb"

解题关键:

字典序: 字符串之间比较和数字比较不一样; 字符串比较是从头往后挨个字符比较,那个字符串大取决于两个字符串中第一个对应不相等的字符; 例如 任意一个a开头的字符串都大于任意一个b开头的字符串;例如字典中apple 大于 book;
题目的意思,你去除重复字母后,需要按最小的字典序返回.并且不能打乱其他字母的相对位置;
例如 bcabc 你应该返回abc, 而不是bca,cab;
例如 cbacdcbc 应该返回acdb,而不是cbad,bacd,adcb
例如 zab,应该返回zab,而不是abz;

思路:

  1. 判断字符串可能出现的特殊情况
  2. 用一个record数组记录字符串中字母出现的次数;
  3. 申请一个字符串栈stack用来存储去除重复字母的结果,并利用它的特性帮助我们找到正确的次序;
  4. 遍历字符串s
  5. 从0~top,遍历stack 判断当前字符s[i]是否存在于栈stack中 如果当前字符是否存在于栈的定义一个falg 标记isExist, 0表示不存在, 1表示存在

6.如果isExist存在,record[s[i]]位置上的出现次数减一,并继续遍历下一个字符; 表示当前的stack已经有这个字符了没有必要处理这个重复的字母;
7.如果isExist不存在,则
如果不存在,则需要循环一个找到一个正确的位置,然后在存储起来;
如果不存在,跳过栈中所有比当前字符大、且后面还会出现的元素,然后将当前字符入栈
top > -1表示栈非空
stack[top] > s[i]表示栈顶元素比当前元素大
record[stack[top]] > 1表示后面还会出现
通过一个while循环找到将栈中位置错误的数据,出栈. 找当前合适的位置,则结束while循环;
找到合理的位置后,则将当前字符s[i]入栈;
8.直到遍历完所有字符后,则为字符串栈stack 添加一个结束符'\0',并返回当前字符串首地址;

答案:

char *removeDuplicateLetters(char *S)
{
    /*
     ① 特殊情况处理,s为空,或者字符串长度为0;
     ② 特殊情况,s的长度为1,则没有必要后续的处理,则直接返回s;
     */
    /*
    if (S == NULL || strlen(S) == 0) {
        return "";
    }
    if (strlen(S) == 1) {
        return S;;
    }
    */
    if (strlen(S) <=1) {
        return S;
    }
    
    /*
     record数组,用来记录字符串s中每个字符未来会出现的次数;
     因为小写字母只有26个,所有只需要开辟26个空间就可以了
    */
    char record[26] ={0};
    int length = (int)strlen(S);
    
     /*申请一个字符串stack;(用栈的特性来进行stack字符串的数据进出)  因为字符串以\0结束标志*/
    char * stack = (char*)malloc(sizeof(char) * length + 1);
    /* memset(void *s, int ch, size_t n) 将stack len*2*sizeof(char)长度范围的空间填充0; */
    memset(stack, 0, length * sizeof(char) + 1);
    
    /* stack 栈顶赋初值为-1 */
    int top = -1;
    
    /*1.统计每个字符的频次 例如bcabc  recod[26] = {1,2,2}*/
    for (int i = 0; i<length; i++) {
        record[S[i] - 'a']++;
    }
    
    /* 2.遍历s,入栈 */
    for (int i = 0; i<length; i++) {
        /* isExist 标记, 判断当前字符是否存在栈中  */
        int  isExist = 0;
        /*
         ①从0~top,遍历stack 判断当前字符s[i]是否存在于栈stack中
          如果当前字符是否存在于栈的flag, 0表示不存在, 1表示存在
          top指向栈顶(也是执行stack字符串最后一个字符的位置,表示字符串长度上限)
         */
       for (int j = 0; j<length; j++) {
           if (S[i] == stack[j]) {
               isExist = 1;
               break;
           }
       }
        //② 如果存在,record[s[i]]位置上的出现次数减一,并继续遍历下一个字符
        //③ 如果不存在,则需要循环一个正确位置存储起来;
        //④ 如果不存在,跳过栈中所有比当前字符大、且后面还会出现的元素,然后将当前字符入栈
        // 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 (isExist == 1) {
            record[S[i] - 'a']--;
        } else {
            while (top > -1 && stack[top] > S[i] && record[stack[top] - 'a'] > 1) {
                /* 跳过该元素,频次要减一 */
                record[stack[top] - 'a']--;
                /* 出栈 */
                top--;
            }
            //⑤ 结束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;
}
int main(int argc, const char * argv[]) {
    // insert code here...
        printf("去掉重复字母! LeetCode-困难 \n");
        
        char *s ;
        s = removeDuplicateLetters("bcabc");
        printf("%s\n",s);
     
        s = removeDuplicateLetters("zab");
        printf("%s\n",s);
    
        s = removeDuplicateLetters("cbacdcbc");
        printf("%s\n",s);
        
        printf("\n");
    return 0;
}

相关文章

  • 数据结构与算法09-字符串去重

    题目: • 去除重复字母(LeetCode-困难)给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得...

  • 数据结构与算法-去除重复字符串,保持字典序最小

    题目: 去除重复字母(LeetCode-困难) 给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每...

  • 去除重复字母

    题目:去除重复字母(LeetCode-困难)给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字...

  • 去除重复字母(LeetCode-困难)

    demo给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序...

  • 去重字符,BF和RK字符匹配

    去重字符,BF和RK字符匹配的算法实现与总结! 题目:去除重复字母(LeetCode-困难) 给你一个仅包含小写字...

  • 去除重复字母

    要求一、要去重。 要求二、去重字符串中的字符顺序不能打乱 s 中字符出现的相对顺序。 要求三、在所有符合上一条要求...

  • LeetCode-python 316.去除重复字母

    题目链接难度:困难 类型: 贪心、栈 给定一个仅包含小写字母的字符串,去除字符串中重复的字母,...

  • 316. 去除重复字母

    题目 316. 去除重复字母 给定一个仅包含小写字母的字符串,去除字符串中重复的字母,使得每个字母只出现一次。需保...

  • 栈思想的应用2

    一、字符串编码 二、去除重复字母

  • 数据结构与算法 练习(八)

    去除重复字母 给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的...

网友评论

      本文标题:去除重复字母(LeetCode-困难)

      本文链接:https://www.haomeiwen.com/subject/tbwyihtx.html