leetcode 1081
开始的思路是遍历存储每个字符的所有位置,再进行扫描处理,但是实际操作并没有很熟练,于是在讨论区学习后,有了下面的解法!
首先需要知道不同的字符在字符串中的最后的位置(理论上的最优位置)
然后扫描字符串进行处理;这里有几个规则:
-
对于不同的字符,字典序靠前的字符应该相对于靠后的字符在位置上尽可能靠前(即index较小);
-
依次扫描字符串,每一次需要看是否在stack中存下了字符ch1,如果没有,需要和栈顶的字符ch2进行比较,如果栈顶的字符ch2在字典序中大于ch1且ch2在字符串中的最后的位置比此时的index大,那么栈顶元素弹出(同时其标志位恢复),将ch1压入stack;否则直接把ch1压入stack;
-
对于一个已经和另外一个字符进行比较确定位置的字符,其位置应该在之后的操作不更改:这里举例:
先扫描e,下一个字符是c,且e的位置无法变更,只能在c的前面,即之前保存的e的最后的位置就是此时的index;继续扫描,下一个字符b和c进行比较,这里,会发现,e相对于b,和e相对于c是一样的道理,甚至,如果c 的最后的位置在此时b的后面,那么我们就把c先取消,这时,e相对于b的位置仍无需变换,eb甚至优于之前的ec
-
对于已经压入栈的字符,再次遇到时不需要处理,因为之前的位置应该是良好的字典序,再次处理然而会导致字符重复且字典序变差;
具体代码如下:
class Solution {
public:
string smallestSubsequence(string text) {
stack<char> st;
vector<int> final(128, 0);
vector<bool> mark(128, 0);
for(int i = 0; i < text.size(); i++) {
final[text[i]] = i;
}
for(int i = 0; i < text.size(); i++) {
if (mark[text[i]])
continue;
while(st.size() and st.top() > text[i] and final[st.top()] > i) {
mark[st.top()] = false;
st.pop();
}
st.push(text[i]);
mark[text[i]] = true;
}
string result = "";
while(st.size() > 0) {
result += st.top();
st.pop();
}
reverse(result.begin(), result.end());
return result;
}
};
以上为参考讨论区的改编!原答案链接