[LeetCode] Strong Password Checker 密碼強度檢查器


 

A password is considered strong if below conditions are all met:

  1. It has at least 6 characters and at most 20 characters.
  2. It must contain at least one lowercase letter, at least one uppercase letter, and at least one digit.
  3. It must NOT contain three repeating characters in a row ("...aaa..." is weak, but "...aa...a..." is strong, assuming other conditions are met).

Write a function strongPasswordChecker(s), that takes a string s as input, and return the MINIMUM change required to make s a strong password. If s is already strong, return 0.

Insertion, deletion or replace of any one character are all considered as one change.

 

這道題給了我們一個密碼串,讓我們判斷其需要多少步修改能變成一個強密碼串,然后給定了強密碼串的條件,長度為6到20之間,必須含有至少一個的小寫字母,大寫字母,數字,而且不能有連續三個相同的字符,給了我們三種修改方法,任意一個位置加入字符,刪除字符,或者是置換任意一個字符,讓我們修改最小的次數變成強密碼串。這道題定義為Hard真是名副其實,博主光是看大神的帖子都看了好久,這里主要是參考了大神fun4LeetCode的帖子,個人感覺這個算是講的十分清楚的了,這里就照搬過來吧。首先我們來看非強密碼串主要有的三個問題:

1. 長度問題,當長度小於6的時候,我們要通過插入字符來補充長度,當長度超過20時,我們要刪除字符。

2. 缺失字符或數字,當我們缺少大寫,小寫和數字的時候,我們可以通過插入字符或者替換字符的方式來補全。

3. 重復字符,這個也是本題最大的難點,因為插入,刪除,或者置換都可以解決重復字符的問題,比如有一個字符串"aaaaa",我們可以用一次置換,比如換掉中間的字符'a';或者兩次插入字符,在第二個a和第四個a后面分別插入一個非a字符;或者可以刪除3個a來解決重復字符的問題。由於題目要求我們要用最少的步驟,那么顯而易見置換是最高效的去重復字符的方法。

我們通過舉例觀察可以知道這三種情況並不是相互獨立的,一個操作有時候可以解決多個問題,比如字符串"aaa1a",我們在第二個a后面增加一個'B',變為"aaBa1a",這樣同時解決了三個問題,即增加了長度,又補充了缺失的大寫字母,又去掉了重復,所以我們的目標就是盡可能的找出這種能解決多種問題的操作。由於情況三(重復字符)可以用三種操作來解決,所以我們分別來看能同時解決情況一和情況三,跟同時解決情況二和情況三的操作。對於同時解決情況一和情況二的操作如果原密碼串長度小於6會有重疊出現,所以我們要分情況討論:

當密碼串長度小於6時,情況一和情況二的操作步驟可以完全覆蓋情況三,這個不難理解,因為這種情況下重復字符個數的范圍為[3,5],如果有三個重復字符,那么增加三個字符的操作可以同時解決重復字符問題("aaa" -> "a1BCaa";如果有四個重復字符,那么增加二個字符的操作也可以解決重復問題("aaaa" -> "aa1Baa");如果有五個重復字符,那么增加和置換操作也同時解決重復問題("aaaaa" -> "aa1aaB")。所以我們就專心看最少多少步能同時解決情況一和情況二,首先我們計算出當前密碼串需要補幾個字符才能到6,補充字符的方法只能用插入字符操作,而插入字符操作也可以解決情況二,所以當情況二的缺失種類個數小於等於diff時,我們不用再增加操作,當diff不能完全覆蓋缺失種類個數時,我們還應加上二者的差值。

當密碼串長度大於等於6個的時候,這種情況就比較復雜了,由於目前字符串的長度只可能超標不可能不達標,所以我們盡量不要用插入字符操作,因為這有可能會使長度超過限制。由於長度的不確定性,所以可能會有大量的重復字符,那么解決情況三就變得很重要了,由於前面的分析,替換字符是最高效的解法,但是這種方法沒法解決情況一,因為長度超標了的話,再怎么替換字符,也不會讓長度減少,但是我們也不能無腦刪除字符,這樣不一定能保證是最少步驟,所以在解決情況三的時候還要綜合考慮到情況一,這里用到了一個trick (很膜拜大神能想的出來),對於重復字符個數k大於等於3的情況,我們並不是直接將其刪除到2個,而是先將其刪除到最近的(3m+2)個,那么如果k正好被3整除,那么我們直接變為k-1,如果k除以3余1,那么變為k-2。這樣做的好處是3m+2個重復字符可以最高效的用替換m個字符來去除重復。那么下面我們來看具體的步驟,首先我們算出超過20個的個數over,我們先把over加到結果res中,因為無論如何這over個刪除操作都是要做的。如果沒超過,over就是0,用變量left表示解決重復字符最少需要替換的個數,初始化為0。然后我們遍歷之前統計字符出現個數的數組,如果某個字符出現個數大於等於3,且此時over大於0,那么我們將個數減為最近的3m+2個,over也對應的減少,注意,一旦over小於等於0,不要再進行刪除操作。如果所有重復個數都減為3m+2了,但是over仍大於0,那么我們還要進一步的進行刪除操作,這回每次直接刪除3m個,直到over小於等於0為止,剩下的如果還有重復個數大於3的字符,我們算出置換字符需要的個數直接加到left中即可,最后我們比較left和missing,取其中較大值加入結果res中即可,參見代碼如下:

                                                                                                     

class Solution {
public:
    int strongPasswordChecker(string s) {
        int res = 0, n = s.size(), lower = 1, upper = 1, digit = 1;
        vector<int> v(n, 0);
        for (int i = 0; i < n;) {
            if (s[i] >= 'a' && s[i] <= 'z') lower = 0;
            if (s[i] >= 'A' && s[i] <= 'Z') upper = 0;
            if (s[i] >= '0' && s[i] <= '9') digit = 0;
            int j = i;
            while (i < n && s[i] == s[j]) ++i;
            v[j] = i - j;
        }
        int missing = (lower + upper + digit);
        if (n < 6) {
            int diff = 6 - n;
            res += diff + max(0, missing - diff);
        } else {
            int over = max(n - 20, 0), left = 0;
            res += over;
            for (int k = 1; k < 3; ++k) {
                for (int i = 0; i < n && over > 0; ++i) {
                    if (v[i] < 3 || v[i] % 3 != (k - 1)) continue;
                    v[i] -= k;
                    over -=k;
                }
            }
            for (int i = 0; i < n; ++i) {
                if (v[i] >= 3 && over > 0) {
                    int need = v[i] - 2;
                    v[i] -= over;
                    over -= need;
                }
                if (v[i] >= 3) left += v[i] / 3;
            }
            res += max(missing, left);
        }
        return res;
    }
};

 

參考資料:

https://discuss.leetcode.com/topic/63854/o-n-java-solution-by-analyzing-changes-allowed-to-fix-each-condition/2

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM