题目:给你一个仅包含小写字母的字符串,请你去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
解题思路:
- 遍历串的字符
- 判断栈中是否已有当前字符
- 如果已经栈里已存在,
- record内该字符出现的次数减一
- 继续遍历串的下一个字符
- 如果栈里不存在
- 循环 ( 栈不为空 + 栈顶字符>当前字符 + 栈顶字符的出现次数>1(即后面还会出现) ):
- record内该字符出现的次数减一
- 栈顶出栈
- 直到不满足循环
- 当前字符入栈
- 循环 ( 栈不为空 + 栈顶字符>当前字符 + 栈顶字符的出现次数>1(即后面还会出现) ):
- 如果已经栈里已存在,
- 栈顶添加'\0' 构成字符串结尾字符(实际栈的存储空间还有其他字符,所以标记\0表示字符串结束)
代码
char *removeDuplicateLetters(char *s)
{
if (s == NULL || strlen(s) == 0) return "";
if (strlen(s) == 1) return s;
// 准备工作:获取字符串长度、创建记录字符串线次数的数组record
int len = (int)strlen(s);
int record[26] = {0};
// 创建栈,用于记录出现的字符
char *stack = (char *)malloc(len * sizeof(char));
memset(stack, 0, len * sizeof(char));
// 栈顶置空
int top = -1;
// 统计字符串中每个字符出现的次数
for (int i = 0; i < len; i++) {
record[s[i]-'a']++;
}
// 遍历每个字符
for (int i = 0; i < len; i++) {
// 1、首先检查栈里是否已有该字符
int isExit = 0;
for (int j = 0; j <= top; j++) {
if (stack[j] == s[i]) {
isExit = 1;
break;
}
}
// 2、判断栈中是否已有当前字符
// ① 如果已经栈里已存在该字符,
// ① record内该字符出现的次数减一
// ② 继续遍历串的下一个字符
// ② 如果栈里不存在
// ① 循环 ( 栈不为空 + 栈顶字符>当前字符 + 栈顶字符的出现次数>1(即后面还会出现) ):
// ① record内该字符出现的次数减一
// ② 栈顶出栈
// ③ 直到不满足循环
// ② 当前字符入栈
// 3、栈顶添加'\0' 构成字符串,处理完成,栈内元素从栈底到栈顶即为结果字符串
if (isExit == 1)
{ // ① 如果已经栈里已存在该字符,
// ① record内该字符出现的次数减一
record[s[i]-'a']--;
}
else
{ // ② 如果栈里不存在
while (top > -1 && stack[top] > s[i] && record[stack[top]-'a'] > 1)
{ // ① 循环 ( 栈不为空 + 栈顶字符>当前字符 + 栈顶字符的出现次数>1(即后面还会出现) ):
// ① record内该字符出现的次数减一
record[stack[top]-'a']--;
// ② 栈顶出栈
top--;
}
top++;
stack[top] = s[i];
}
}
stack[++top] = '\0';
return stack;
}
int main(int argc, const char * argv[]) {
char *resultString;
char *originString = "bcabc";
printf("输入:%s\n",originString);
resultString = removeDuplicateLetters(originString);
printf("输出:%s\n",resultString);
return 0;
}