从字符串中删除所有重复项,并选择可能的字典最小字符串。例如,字符串cbacdcbc将返回acdb,而不是adcb。
因此,如果我们不必选择字典最小的字符串,那么这有一个相对简单的解决方案,但考虑到这一事实,我不确定如何找到有效的解决方案。这是我到目前为止所做的:
string removeDuplicateLetters(string s)
{
vector<bool> v(26,0);
for(int i = 0; i < s.size(); i++) {
v[s[i]-'a'] = 1;
}
string ss = "";
for(int i = 0; i < s.size(); i++) {
if(v[s[i]-'a']) {
ss += s[i];
v[s[i]-'a'] = 0;
}
}
return ss;
}
答案 0 :(得分:3)
<强>算法强>
a,b,c,d
。 a
的第一个b,c,d
或者,如果无法做到这一点,请找到其后全部为b
的第一个a,c,d
或者,如果无法做到这一点,请找到其后全部为c
的第一个a,b,d
或者,如果不可能,请找到第一个d
。 代码示例
(在Javascript中;我的C ++生锈了)。它创建了一个位模式chars
来存储仍然可以找到的字符,以及一个数组after
的位模式,用于存储每个位置后仍然可用的字符。
function smallestString(input) {
var chars = 0, after = [];
for (var i = input.length - 1; i >= 0; i--) {
chars |= 1 << (input.charCodeAt(i) - 97);
after[i] = chars;
}
var result = "", start = 0, pos;
while (chars) {
for (var i = 0; i < 26; i++) {
if (chars & (1 << i)) {
pos = input.indexOf(String.fromCharCode(97 + i), start);
if (chars == (chars & after[pos])) {
result += String.fromCharCode(97 + i);
chars -= 1 << i;
break;
}
}
}
start = pos + 1;
}
return result;
}
document.write(smallestString("cbacdcbc") + "<BR>");
document.write(smallestString("thequickbrownfoxjumpsoverthelazydog"));
答案 1 :(得分:0)
算法草图。
传递字符串,构建每个字符出现次数的映射,以及每个字符最右边(也可能是唯一)出现的位置。
找到可以出现在第一个位置的最小字符。要做到这一点,从左到右,注意遇到的最小字符;当你碰到任何角色的最右边时,就停止。删除最小字符之前的所有字符,以及最小字符的所有其他副本;相应地更新地图。
从第2步中最小的一个字符开始重复。
一旦地图中的所有计数器达到1,就可以提前终止。其他副本的删除可以与正常迭代结合使用(只需在计数器映射中标记要删除0的字符,在正常搜索中跳过它们,删除前缀时删除它们。
这种算法在最坏的情况下是二次的,至少在字母表的大小(最坏的情况是abc...zabc...
;算法检查每个字符的一半字符串,只决定保留它)。我认为这可以通过在一种优先级队列结构中保持跟踪不仅是最小的,也可以是第二小和第三小的等等来解决(详细信息留给读者阅读)。
答案 2 :(得分:0)
m69在c ++中的javascript:
string smallestString(string input) {
int chars = 0;
int after[sizeof(input)];
for (int i = input.length() - 1; i >= 0; i--) {
chars |= 1 << (input[i] - 97);
after[i] = chars;
}
string result = "";
int start = 0, pos;
while (chars) {
for (int i = 0; i < 26; i++) {
if (chars & (1 << i)) {
pos = input.find('a' + i, start);
if (chars == (chars & after[pos])) {
result += 'a' + i;
chars -= 1 << i;
break;
}
}
}
start = pos + 1;
}
return result;
}
答案 3 :(得分:0)
我发现这种方法很简单。
首先找到每个字符的数量。
输入:s
vector<int> cnt(26);
int n=s.size();
for(int i=0;i<n;i++) cnt[s[i]-'a']++;
有一个访问过的向量vector<bool> visit(26);
string ans="";
for(int i=0;i<n;i++){
int t=s[i]-'a';
cnt[t]--;
if(visit[t]) continue;
while(ans.size()>0 && s[i]<ans.back() && cnt[ans.back()-'a']>0){
visit[ans.back()-'a']=false;
ans.pop_back();
}
ans.push_back(s[i]);
visit[t]=true;
}
return ans;
时间复杂度为O(n)