【数据结构与算法】-(8.1)字符串去重算法


【数据结构与算法】-(1)基础篇

【数据结构与算法】-(2)线性表基础

【数据结构与算法】-(3)循环链表(单向)

【数据结构与算法】-(4)双向链表和双向循环链表

【数据结构与算法】-(5)链表面试题解析

【数据结构与算法】-(6)栈

【数据结构与算法】-(7)队列

【数据结构与算法】-(8)栈之算法题

去除重复字母

LeetCode 级别:困难

Q: 题目

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

示例1:

输入:"bcabc"

输出:"abc"

示例2:

输入:"cbacdcbc"

输出:"acdb" ~~cbad~~, ~~bacd~~, ~~adcb~~

Analyze:

分析关键字:字典序不打乱

  • 字典序最小:即排列顺序按照26个字母一次排序,比如给的antman 肯定要排在ultraman 前面
  • 不打乱排序:即去除重复字母后,未被重复的那部分字母,不改变原来位置。比如bcabc 结果是 abc 那么去除的是第1、第2位的bc, 后面3位abc 依然不变。

A:思路:

  1. 给定字符串 s ,排除字符串异常情况;

  2. 使用一个record 数组,来记录字符串中字母出现的次数;

  3. 创建一个栈stack ,用来存储去除重复字母的结果,并利用它的特性帮助我们找到正确的次序。

  4. 遍历给定的字符串s

  5. 从0~top 依次遍历 stack,判断当前的字符s[i] 是否存在于stack 中,用一个int类型的值isExist来表示是否存在。

    1. 如果isExsit 存在,即==1,将record [s[i]] 位置上出现次数减1,即record[s[i]]--,并继续遍历下一个字符;意思是,当前的stack 已经包含这个字符,以后都不需要继续处理这个字符了。

    2. 如果isExist 不存在,则需要while循环一下,找到这个字符正确的位置,然后存储起来。循环规则大概是这样:跳过栈中比当前字符大、而且后面还会出现的元素,将字符入栈。

      while 循环的条件如下:

      1. top > -1 来保证栈不为空
      2. stack[top] > s[i] 表示栈定元素比当前元素大
      3. record[stack[top]] > 1 表示后面还会出现
  6. 等遍历完所有的字符后,对当前的字符栈stack 添加一个结束符\0,并返回当前字符串首地址;

    代码实现

char *removeDuplicateLetters(char *s)
{
    /*
     ① 特殊情况处理,s为空,或者字符串长度为0;
     ② 特殊情况,s的长度为1,则没有必要后续的处理,则直接返回s;
     */
    if (s == NULL || strlen(s) == 0) {
        return "";
    }
    if (strlen(s) == 1) {
        return s;
    }

    //record数组,用来记录字符串s中每个字符未来会出现的次数;
    char record[26] = {0};
    int len = (int)strlen(s);

    //申请一个字符串stack;(用栈的特性来进行stack字符串的数据进出)
    char* stack = (char*)malloc(len * 2 * sizeof(char));
    //memset(void *s, int ch, size_t n) 将stack len*2*sizeof(char)长度范围的空间填充0;
    memset(stack, 0, len * 2 * sizeof(char));
    //stack 栈顶赋初值为-1;
    int top = -1;

    //1.统计每个字符的频次
    //例如bcabc  recod[26] = {1,2,2};
    int i;
    for (i = 0; i < len; i++) {
        record[s[i] - 'a']++;
    }

    //2.遍历s,入栈
    for (i = 0; i < len; i++) {


        //isExist 标记, 判断当前字符是否存在栈中;
        int isExist = 0;

        //①从0~top,遍历stack 判断当前字符s[i]是否存在于栈stack中
        //如果当前字符是否存在于栈的flag, 0表示不存在, 1表示存在
        //top指向栈顶(也是执行stack字符串最后一个字符的位置,表示字符串长度上限)
        for (int j = 0; j <= top; 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;
}

试着执行一下代码:

    char *s ;
    s = removeDuplicateLetters("zdzdaabc");

结果如下:

zdzdaabc = > dzabc ,符合要求 ✅

提交结果

leetcode 双百,可以可以


文章作者: 李佳
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 李佳 !
评论
 上一篇
【数据结构与算法】-(8.2)字符串搜索算法和RK&BP算法 【数据结构与算法】-(8.2)字符串搜索算法和RK&BP算法
【数据结构与算法】-(1)基础篇 【数据结构与算法】-(2)线性表基础 【数据结构与算法】-(3)循环链表(单向) 【数据结构与算法】-(4)双向链表和双向循环链表 【数据结构与算法】-(5)链表面试题解析 【数据结构与算法】-(6)栈
2020-04-22 李佳
下一篇 
【数据结构与算法】-(8)栈之算法题 【数据结构与算法】-(8)栈之算法题
【数据结构与算法】-(1)基础篇 【数据结构与算法】-(2)线性表基础 【数据结构与算法】-(3)循环链表(单向) 【数据结构与算法】-(4)双向链表和双向循环链表 【数据结构与算法】-(5)链表面试题解析 【数据结构与算法】-(6)栈
2020-04-20 李佳
  目录