首页 > 技术文章 > leetcode 1081

xiaomaoaichiyu 2019-09-13 23:48 原文

开始的思路是遍历存储每个字符的所有位置,再进行扫描处理,但是实际操作并没有很熟练,于是在讨论区学习后,有了下面的解法!

首先需要知道不同的字符在字符串中的最后的位置(理论上的最优位置)

然后扫描字符串进行处理;这里有几个规则:

  1. 对于不同的字符,字典序靠前的字符应该相对于靠后的字符在位置上尽可能靠前(即index较小);

  2. 依次扫描字符串,每一次需要看是否在stack中存下了字符ch1,如果没有,需要和栈顶的字符ch2进行比较,如果栈顶的字符ch2在字典序中大于ch1且ch2在字符串中的最后的位置比此时的index大,那么栈顶元素弹出(同时其标志位恢复),将ch1压入stack;否则直接把ch1压入stack;

  3. 对于一个已经和另外一个字符进行比较确定位置的字符,其位置应该在之后的操作不更改:这里举例:

    先扫描e,下一个字符是c,且e的位置无法变更,只能在c的前面,即之前保存的e的最后的位置就是此时的index;继续扫描,下一个字符b和c进行比较,这里,会发现,e相对于b,和e相对于c是一样的道理,甚至,如果c 的最后的位置在此时b的后面,那么我们就把c先取消,这时,e相对于b的位置仍无需变换,eb甚至优于之前的ec

  4. 对于已经压入栈的字符,再次遇到时不需要处理,因为之前的位置应该是良好的字典序,再次处理然而会导致字符重复且字典序变差;

具体代码如下:

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;
    }
};

以上为参考讨论区的改编!原答案链接

https://leetcode.com/problems/smallest-subsequence-of-distinct-characters/discuss/344686/CPP-or-EASY-or-100-BEATS-TIME-AND-MEM-or-SMALL

推荐阅读