选择删除重复项后词典中最小的字符串
Select lexicographical smallest string after duplicates removed
从字符串中删除所有重复项,并选择字典中可能的最小字符串。例如,字符串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;
}
算法
- 检查输入字符串中存在哪些字母:
a,b,c,d
- 查找后面有所有
b,c,d
的第一个a
。
或者,如果不可能,请查找第一个后面有所有a,c,d
的b
。
或者,如果不可能,请查找第一个后面有所有a,b,d
的c
。
或者,如果不可能,请查找第一个d
- 放弃输入字符串的开头,直到选定的字符
- 对要查找的其余字符重复步骤2
代码示例
(用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"));
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;
}
算法草图。
-
传递字符串,构建每个字符出现次数的映射,以及每个字符最右边(可能也是唯一一个)出现的位置。
-
找到可以出现在第一个位置的最小字符。要执行此操作,请从左到右,注意遇到的最小字符;当你击中任何角色的最右边时停止。删除最小字符之前的所有字符,以及最小字符的所有其他副本;相应地更新地图。
-
从步骤#2中最小的字符后面的字符开始重复。
一旦映射中的所有计数器达到1,就可以提前终止。删除其他副本可以与正常迭代相结合(只需在计数器映射中用0标记要删除的字符,在正常搜索中跳过它们,在删除前缀时删除它们)。
这种算法在最坏的情况下是二次的,至少在字母表的大小上是这样(最坏的是abc...zabc...
;该算法为每个字符检查一半的字符串,但决定保留它)。我认为这可以通过在一种优先级队列结构中跟踪最小的,还有第二小的和第三小的等等来解决(细节留给读者练习)。
我发现这种方法很简单。
首先找到每个字符的计数。
输入: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)
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 如何从给定字符串中删除第二次和第三次出现的$
- 在C++的字符串中搜索和删除某些字符
- 从 C 样式字符串中删除子字符串 "in place" 在C++代码中
- 使用另一个字符串从字符串中删除空格
- 删除/替换C++字符串中的多字符 (ÿû)
- 删除所有字符串后如何恢复 QStringList?
- 如何删除字符串中的前 2 个字符(如果它有"-")
- 根据新的行分隔符从字符串中删除子字符串
- C ++,如何从控制台中输入的字符串中删除字母?
- 删除字符串后C++检测到堆损坏
- 我正在尝试使用 while 循环从字符串中删除字母,直到没有字母。我在这里做错了什么?
- 如何在 c++ 中删除字符串中的某些字符?
- 删除字符串数组
- 删除字符串中具有相同值的任何相邻字母"pair"
- 高效的字符串截断算法,按顺序删除相等的前缀和后缀
- 如何使用双黑斜杠从字符串中删除单反斜杠
- 如何在编译时从string_view中删除子字符串?
- 从文件中读取多行.txt字符串删除空格并创建新文件进行输出
- c字符串 删除非字母/非空格字符 - C++