leetcode 2030. 含特定字母的最小子序列

特别恶心的一道题
首先基础做法是单调栈,如果没有至少repetition个letter的限制,直接从左往右遍历,维护一个递增栈即可

加上这个限制之后,会有两个改动:

  1. 判断是否当前出栈元素是letter,删除后会导致后面的letter不够凑到repetition,这里需要把原栈的所有元素进行归档(代码31行)
  2. 处理一直是递增字符串的特殊case

代码如下

class Solution {
public:
    string smallestSubsequence(string s, int k, char letter, int repetition) {
        string result;

        int n = s.length();
        stack<char> st;
        int letter_count = 0;

        int need_delete = n - k;
        // int last_repetition = 0;
        

        vector<int> pre(n + 5, 0);
        for(int i = 0; i < n; ++i) {
            if (i == 0) pre[i] = s[i] == letter;
            else pre[i] = pre[i - 1] + (s[i] == letter);
        }
        
        int end_flag = n;

        for(int i = 0; i < n; ++i) {
            int still_have = pre[n - 1] - pre[i] + (s[i] == letter);

            // printf("%d\n", still_have);

            while(!st.empty()) {
                char tt = st.top();

                if (need_delete == 0) break;
                if (tt == letter && letter_count - 1 + still_have < repetition) {
                    string tmp;
                     while(!st.empty()) {
                        tmp += st.top();
                        st.pop();
                    }
                    reverse(tmp.begin(), tmp.end());
                    result += tmp;
                    // printf("%s\n", result.c_str());
                    break;
                }

                if(tt > s[i]) {
                    st.pop();
                    need_delete --;
                    if(tt == letter) letter_count --;
                    // printf("pop %c %d %d\n", tt, need_delete, letter_count);
                } else {
                    break;
                }
            }

            st.push(s[i]);
            if(s[i] == letter) letter_count ++;
            // printf("push %c %d %d\n", s[i], need_delete, letter_count);
        }


        string tmp;
        while(!st.empty()) {
            tmp += st.top();
            st.pop();
        }
        reverse(tmp.begin(), tmp.end());
        result += tmp;

        // printf("%s\n", result.c_str());

        
        result = result.substr(0, k);

        // for special case
        int cnt = 0;
        for(int i = 0; i < k; ++i) {
            if(result[i] == letter) {
                cnt ++;
            }
        }
        for(int i = k - 1; i >= 0; --i) {
            if(result[i] != letter && cnt < repetition) {
                result[i] = letter;
                cnt ++;
            }
        }

        return result;
    }
};
posted @ 2021-12-25 14:18  basasuya  阅读(42)  评论(0编辑  收藏  举报