420. 强密码检验器
难点:当总长度超过20时,如何在删除的同时将长度大于等于3的连续子串一并消掉是个问题,如果有多个这样的子串,选哪些来消除?顺序如何?
考虑每个连续子串的长度,根据模3的余数进行分类len % 3 == 0
时,仅仅删除1个字符就能等效于一次修改操作len % 3 == 1
时,需要删除2个字符等效于一次修改操作len % 3 == 2
时,每次删除3个字符等效于一次修改操作
做法是在寻找连续子串的同时,记录其类别以及仅用修改操作需要的次数
之后根据要删除的字符数用等效替换的方式更新修改所需次数。
class Solution {
public int strongPasswordChecker(String s) {
boolean a = false, b = false, c = false;
int n = s.length();
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (ch >= '0' && ch <= '9') a = true;
else if (ch >= 'a' && ch <= 'z') b = true;
else if (ch >= 'A' && ch <= 'Z') c = true;
}
int k = 0;
if (a) k++;
if (b) k++;
if (c) k++;
if (n < 6) return Math.max(6 - n, 3 - k);
else {
int p = 0, del = n - 20, res = del;
int[] d = new int[3];
for (int i = 0; i < n; i++) {
int j = i;
while (j < n && s.charAt(j) == s.charAt(i))
j++;
if (j - i >= 3) {
d[(j - i) % 3]++;
p += (j - i) / 3;
}
i = j - 1;
}
if (n <= 20) return Math.max(3 - k, p);
else {
if (d[0] > 0 && del > 0) {
int t = Math.min(d[0], del);
p -= t;
del -= t;
}
if (d[1] > 0 && del > 0) {
int t = Math.min(d[1], del / 2);
del -= t * 2;
p -= t;
}
if (p > 0 && del > 0) {
int t = Math.min(p, del / 3);
del -= t * 3;
p -= t;
}
return res + Math.max(p, 3 - k);
}
}
}
}