420. 强密码检验器

难点:当总长度超过20时,如何在删除的同时将长度大于等于3的连续子串一并消掉是个问题,如果有多个这样的子串,选哪些来消除?顺序如何?
考虑每个连续子串的长度,根据模3的余数进行分类
len % 3 == 0时,仅仅删除1个字符就能等效于一次修改操作
len % 3 == 1时,需要删除2个字符等效于一次修改操作
len % 3 == 2时,每次删除3个字符等效于一次修改操作
做法是在寻找连续子串的同时,记录其类别以及仅用修改操作需要的次数
之后根据要删除的字符数用等效替换的方式更新修改所需次数。

  1. class Solution {
  2. public int strongPasswordChecker(String s) {
  3. boolean a = false, b = false, c = false;
  4. int n = s.length();
  5. for (int i = 0; i < n; i++) {
  6. char ch = s.charAt(i);
  7. if (ch >= '0' && ch <= '9') a = true;
  8. else if (ch >= 'a' && ch <= 'z') b = true;
  9. else if (ch >= 'A' && ch <= 'Z') c = true;
  10. }
  11. int k = 0;
  12. if (a) k++;
  13. if (b) k++;
  14. if (c) k++;
  15. if (n < 6) return Math.max(6 - n, 3 - k);
  16. else {
  17. int p = 0, del = n - 20, res = del;
  18. int[] d = new int[3];
  19. for (int i = 0; i < n; i++) {
  20. int j = i;
  21. while (j < n && s.charAt(j) == s.charAt(i))
  22. j++;
  23. if (j - i >= 3) {
  24. d[(j - i) % 3]++;
  25. p += (j - i) / 3;
  26. }
  27. i = j - 1;
  28. }
  29. if (n <= 20) return Math.max(3 - k, p);
  30. else {
  31. if (d[0] > 0 && del > 0) {
  32. int t = Math.min(d[0], del);
  33. p -= t;
  34. del -= t;
  35. }
  36. if (d[1] > 0 && del > 0) {
  37. int t = Math.min(d[1], del / 2);
  38. del -= t * 2;
  39. p -= t;
  40. }
  41. if (p > 0 && del > 0) {
  42. int t = Math.min(p, del / 3);
  43. del -= t * 3;
  44. p -= t;
  45. }
  46. return res + Math.max(p, 3 - k);
  47. }
  48. }
  49. }
  50. }