420. Strong Password Checker [leetcode]

思路:
有三個問題需要解決:
1、缺失字符種類問題(大寫,小寫、數字) 可用操作:replace,insert
2、長度問題 可用該操作:insert(< 6),delete(> 20)
3、重複問題 可用操作: replace,insert,delete,其中replace的解決方法最優。

可以看到各種問題之間是有重複性的,也就是說可以通過解決某個問題,同時解決另一個問題。
我們試圖找到一種途徑能夠在解決一個問題的同時解決(或者說緩解)其他問題。
根據觀察:
長度小於6時,解決問題2的同時,可以解決(緩解)1,3,因此先考慮2,再利用2解決1,3。
長度大於20時,解決問題1可以緩解3(delete),解決問題2也可以緩解3(replace),由於replace操作並不能減少delete操作的步數,而delete操作可以減少(緩解)replace的操作步數,delete應當優先於replace操作(比如……AAA,先delete成……AA,就可以減少一步replace的操作了)。
長度<=20,>=6時,可通過解決1來解決3(優先replace)。

因此我們分情況討論:

首先對於小於6的情況,必須的操作爲insert。 根據推理,需要的操作步數爲: step = 缺失字符種類數 + 字符串長度 > 6 ? 缺失字符種類數 : 6 - 字符串長度

對於大於20的情況,我們首先先解決多餘出來的字符,delete操作必須要保證能最大限度地緩解問題,也就是使得之後重複字符串中需要replace的步數最少。我們儘量保證所有連續的字符串能變成(長度 % 3) = 2的狀態。我們首先通過一步delete使得將每個長度爲3的倍數的連續字符串變成 (長度 % 3) = 2的狀態,然後再通過兩步delete,使得每個 (長度 % 3) = 1 的連續字符串變成 (長度 % 3) = 2的狀態,再通過三步delete 使得每個 (長度 % 3) = 2 的連續字符串變成 (長度 % 3) = 2的狀態。
完成delete後由於長度變成了<=20. 我們可以將問題轉化成<=20,>=6的情況:

檢查問題1,計算出所需要的解決步驟step1,檢查是否有問題3,計算出需要的解決步驟step3, 若step3 <= step1, 則我們只要解決問題1就能徹底解決問題3,因此最後的step = step1;若step3 > step1, 則說明,解決問題1能解決部分問題3,最後所需step = step3;

以下爲代碼部分:

class Solution {
public:
    int strongPasswordChecker(string s) {
        bool upper = false, lower = false, digit = false;
        int step = 0;
        vector<int> repeat;
        int start = 0;
        int size = s.size();
        for (int i = 0; i < s.size(); i++) {
            if (s[i] >= 'A' && s[i] <= 'Z')
                upper = true;
            else if (s[i] >= 'a' && s[i] <= 'z' )
                lower = true;
            else if (s[i] >= '0' && s[i] <= '9')
                digit = true;
            start = i;
            while (i < s.size() - 1 && s[i] == s[i + 1]){
                i++;
            }
            if (i - start >= 2) 
                repeat.push_back(i - start + 1); 
        }
        if (upper && lower && digit && repeat.size() == 0 && size <= 20 && size >= 6) return 0;
        int must = 0;
        if (!upper) must++;
        if (!lower) must++;
        if (!digit) must++;
        step += must;

        if (size < 6) {
            if (size + must < 6) step = 6 - size;  
        }
        else {
        // 解決 overLength  的問題(>20)
            int overLen = size - 20 > 0 ? size - 20 : 0;
            for (int i = 0; i < 3 && overLen; i++) {
                for (vector<int>::iterator it = repeat.begin(); it != repeat.end() && overLen; ) {
                    if ( *it % 3 == i) {
                        int tmp =  ((i + 1) > overLen) ? overLen : (i + 1);
                        *it -= tmp;
                        overLen -= tmp;
                        step += tmp;
                        if (*it < 3) {
                            it = repeat.erase(it);
                            continue;
                        } 
                    }
                    it++;
                }
            }
            step += overLen;
            //此時長度 >= 6, <= 20
            int left = 0;
            for (auto i : repeat)
                left += i / 3;
            step += left > must ? left - must : 0; 
        }
        return step;

    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章