思路:
有三個問題需要解決:
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;
}
};