想了下,这个题用greedy算法解。有点类似dijkstra算法求最短路径。
首先用一个priority queue来装已经发现的字符串,按照字典序排序。
比如输入是cbacdcbc,
scan到了第三个字符的时候,p_queue里面只有一个值 cba。
当scan到第四个字符c的时候,有了重复。这个时候有两个选择:
a. 把 c 从 cba 里面删除,变成 bac。
b. 不理会新遇到的 c,还是 cba。
把a选项和b选项再重新丢回p_queue。
如此重复一直到字符串结尾。返回p_queue的第一个值。因为p_queue是一个按照字典序
排好的priority queue,所以返回的结果一定就是答案。
伪代码如下:
let q = p_queue
for each c in string:
let s = q.empty() ? "" : q.dequeue()
if not c in s
s += c
q.push(s)
else:
s1 = del c in s
s1 += c
q.push(s)
q.push(s1)
return q.empty() ? "" : q.dequeue()
关键是第四行 if not c in s,还有第八行,del c in s,要选好data structure。用
一个linkedhashset可以实现O(1)的查询,删除和插入。p_queue没办法,只能是O(
nlogn)。
最终时间复杂度是O(nlogn),用掉O(n^2)的空间。。。
实现的代码:
string find_smallest_unique_string(const string& str) {
if (str.empty()) {
return "";
}
priority_queue q;
q.push("");
for (char c : str) {
unique_char_string s = q.dequeue();
if (s.find(c) == s.end()) {
q.append(c);
q.push(s);
} else {
q.push(s);
s.erase(c);
s.append(c);
q.push(s);
}
}
unique_char_string s = q.dequeue();
return string(s.begin(), s.end());
}