给定一个仅包含小写字母的字符串,去除字符串中重复的字母,使得每个字母只出现一次。需保证返回结果的字典序最小(要求不能打乱其他字符的相对位置)。
示例 1:
输入: “bcabc”
输出: “abc”
示例 2:
输入: “cbacdcbc”
输出: “acdb”
我的代码 超时
class Solution {
public:
string min_s="zzzzzzz";
int search(string s,char c)
{
for(int i=0;i<s.size();i++)
if(s[i]==c)
return i;
return -1;
}
void dfs(string temp,string &s,int t)
{
if(s.size()==t)
{
if(temp<min_s)
min_s=temp;
return;
}
int index=search(temp,s[t]);
if(index==-1)
{
temp+=s[t];
dfs(temp,s,t+1);
}
else
{
string old=temp;
old.erase(index,1);
string news=temp+s[t];
news.erase(index,1);
dfs(news,s,t+1);
if(news>old)
{
dfs(temp,s,t+1);
}
}
}
string removeDuplicateLetters(string s) {
if(s.size()==0) return s;
string t="";
t+=s[0];
dfs(t,s,1);
return min_s;
}
};
网上的代码 12ms
class Solution {
public:
string removeDuplicateLetters(string s) {
//m[i]用于标记字符i出现了过少次
//visited[i]用于标记字符i是否已经写入结果
int m[256] = {0}, visited[256] = {0};
string res = "0";
//第一次扫描字符串,标记各个字符出现的次数
for (auto a : s){
m[a] += 1;
}
//第二次扫描字符串,写入结果
for (auto ch : s) {
m[ch] -= 1;//出现的次数自减
if (visited[ch])//如果这个字符已经写入结果
continue;
//如果出现比res之前写入的字符还小的字符,且这个写入的字符之后还出现过
while (ch < res.back() && m[res.back()]) {
//将之前写入的记过倒出
visited[res.back()] = 0;
res.pop_back();
}
res += ch;//写入
visited[ch] = 1;//标记已写入
}
return res.substr(1);//去掉开头的字符0
}
};