1. 程式人生 > 實用技巧 >【LeetCode/LintCode】 題解丨阿里高頻面試題:密碼強度檢查器

【LeetCode/LintCode】 題解丨阿里高頻面試題:密碼強度檢查器

當以下條件都滿足時,一個密碼被視為是強密碼:

  1. 至少包含6個字元,但不超過20個字元。
  2. 至少包含一個小寫字母,一個大寫字母,和一個數字。
  3. 不能包含三個連續的重複字元("...aaa..."是弱密碼,但"...aa...a..."是強密碼,假設它們的其他條件都滿足了)。

寫一個函式strongPasswordChecker(s),它將一個字串s作為輸入,並且返回將其轉換成強密碼需要的最少改變次數。如果s已經是一個強密碼了,返回0。

插入、刪除或者替換任意一個字元都視為一次改變。

線上評測地址:點選此處前往

樣例 1:

輸入:"aaa123"
輸出:1
解釋:"aaa123"->"aaA123"

樣例 2:

輸入:"a"
輸出:5
解釋:"a"->"aa"->"aaA"->"aaA1"->"aaA12"->"aaA123"

【題解】

考點:

  • 思維

題解:本題根據要求最小的改變次數,確定修改策略即可。

變為強密碼需要解決三種問題:

  • 長度小於6時需要插入字元,長度大於20時需要刪除字元
  • 缺失字元或數字,此時可以通過插入或者替換字元解決
  • 出現三個及以上重複字元,利用置換解決該問題會更好,可以同時做到解決情況二和情況三。

接下來,按照長度進行討論。

  • 當長度小於6時,儘量採用插入操作,既可以增加長度也可以避免重複字元連續。
  • 當長度大於等於6時,對於重複字元個數k大於等於3的情況,先將其刪除到最近的(3m+2)個,那麼如果k正好被3整除,那麼我們直接變為k-1,如果k%3=1,那麼變為k-2。這樣做的好處是3m+2個重複字元可以用替換m個字元來去除重複,然後遍歷一次,進行刪除和替換,可以直接刪除3m個,最少刪除操作。
public class Solution {
    /**
     * @param s: a string
     * @return: return an integer
     */
    public int strongPasswordChecker(String s) {
        // write  your code here
        int res = 0, n = s.length(), lower = 1, upper = 1, digit = 1;
        int [] v = new int [n];
         for (int i = 0; i < n;) {		//遍歷是否存在缺失字元種類
            if (s.charAt(i) >= 'a' && s.charAt(i) <= 'z') {
                lower = 0;
            }
            if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') {
                upper = 0;
            }
            if (s.charAt(i) >= '0' && s.charAt(i) <= '9') {
                digit = 0;
            }
            int j = i;
            while (i < n && s.charAt(i) == s.charAt(j)) {
                ++i;
            }
            v[j] = i - j;	//標記j位置開始連續重複字元的數量
        }
        int missing = (lower + upper + digit);	 //缺失的字元種類數
        if (n < 6) {
            int diff = 6 - n;					//缺失的長度
            res += diff + Math.max(0, missing - diff);	//缺失長度加上missing - diff差值(因為增加的字元不一定補全字元種類,替換)
        } 
        else {
            int over = Math.max(n - 20, 0), left = 0;	//超出長度
            res += over;
            for (int k = 1; k < 3; ++k) {		 //如果重複數量k%3==0,-1達到3m+2。如果k%3==1,-2達到3m+2
                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;		//通過-2得到3m
                    v[i] -= over;
                    over -= need;			//直接選擇刪除3m個
                }
                if (v[i] >= 3)  {		//如果v[i]>=3那麼需要進行替換操作
                    left += v[i] / 3;
                }
            }
            res += Math.max(missing, left);	//每次除以3即為替換的字元個數
        }
        return res;
        
    }
}

更多題解參見:九章演算法官網