420. 强密码检验器题解
题目来源:420. 强密码检验器
2022.04.02 每日一题
LeetCode 题解持续更新中Github仓库地址 CSDN博客地址
今天的题目是一个Hard
,我觉得可能是因为麻烦吧
对于这个密码,我们可以进行分类讨论
首先 定义 n 是 字符串的长度 ,定义变量 m 是字符串中字符的种类(大写字符,小写字符,数字)
首先判断字符串的长度,这个分为三类
-
长度小于6
在这个范围之中,密码的长度不满足要求,如果遇到了连续三个的字符要进行删除操作,就需要有一个添加的操作,使得密码的长度满足要求。因此我们可以使用
替换
来代替这个操作,因此当长度小于6的时候,他的最少的操作次数就是max(6-n.3-m) -
长度在6和20之间
在这个范围之中,增加的操作是为了破坏连续三个子串或者增加字符的种类,而删除操作时为了破坏连续三个子串,这两个操作都可以使用替换进行操作,替换操作,如果遇到连续的字符串,每三个进行一次操作,从而得到的最少操作次数就是字符相差的个数与 将密码中所有的三个一样的字符删除的个数的最大值
-
长度大于20
这种情况之下,如果进行一个添加操作就需要进行一次删除操作,从而保持密码字符串的长度与题目所说的要求相符合,因此可以使用 替换进行操作,为了使字符串的长度满足题目要求,我们应该首先删除 连续的三个字符在不考虑余数的情况下,每删除 33 个字符,能够连带的减少一次「替换」操作。因此我们可以根据 连续三个的字符串的个数对 3 取模进行统计,得到 cnts,最终的「替换」操作数 tot。除了可变的「替换」操作以外,我们不可避免还需要 base = n - 20base=n−20 的「删除」操作,最少操作次数可以归纳到 n-20+ max(tot, 3 - m)
class Solution { public: int strongPasswordChecker(string password) { // 创建数组,统计各个类型的变量 bool cnt[3]; // 将密码字符串转换成为字符数组 // 取得字符串的长度,后续由长度进行判断 int n = password.length(); // 遍历数组,统计各个类型是否存在 for (int i = 0; i < n; i++) { if (password[i] <= 'z' && password[i] >= 'a') cnt[0] = true; else if (password[i] <= 'Z' && password[i] >= 'A') cnt[1] = true; else if (password[i] <= '9' && password[i] >= '0') cnt[2] = true; } // 创建变量 sum 统计各个类型的是否齐全 int sum = 0; for (bool c : cnt) if (c) sum++; // 如果字符串的长度小于 6 ,就返回替换 和 添加的最大值 if (n < 6) return max(6 - n, 3 - sum); if (n <= 20) { // 创建变量统计连续三个相同字符的个数(替换的个数) int tot = 0; // 统计相同字符的个数 for (int i = 0; i < n; ) { int j = i; while (j < n && password[j] == password[i]) j++; int c = j - i; if (c >= 3) tot += c / 3; i = j; } return max(tot, 3 - sum); } // 现在要讨论的是字符串的长度大于 20 的情况 int tot = 0; int cnts[3]; // 统计 3个连续字符的个数 for (int i = 0; i < n; ) { int j = i; while (j < n && password[j] == password[i]) j++; int c = j - i; if (c >= 3) { tot += c / 3; cnts[c % 3]++; } i = j; } // 用变量 base 统计需要删除的字符个数 int base = n - 20, cur = base; for (int i = 0; i < 3; i++) { if (i == 2) cnts[i] = tot; if (cnts[i] != 0 && cur != 0) { int t = min(cnts[i] * (i + 1), cur); cur -= t; tot -= t / (i + 1); } } return base + max(tot, 3 - sum); } };
class Solution { public int strongPasswordChecker(String password) { // 创建数组,统计各个类型的变量 boolean[] cnt = new boolean[3]; // 将密码字符串转换成为字符数组 char[] a = password.toCharArray(); // 取得字符串的长度,后续由长度进行判断 int n = password.length(); // 遍历数组,统计各个类型是否存在 for (int i = 0; i < n; i++) { if (a[i] <= 'z' && a[i] >= 'a') cnt[0] = true; else if (a[i] <= 'Z' && a[i] >= 'A') cnt[1] = true; else if (a[i] <= '9' && a[i] >= '0') cnt[2] = true; } // 创建变量 sum 统计各个类型的是否齐全 int sum = 0; for (boolean c : cnt) if (c) sum++; // 如果字符串的长度小于 6 ,就返回替换 和 添加的最大值 if (n < 6) return Math.max(6 - n, 3 - sum); if (n <= 20) { // 创建变量统计连续三个相同字符的个数(替换的个数) int tot = 0; // 统计相同字符的个数 for (int i = 0; i < n; ) { int j = i; while (j < n && a[j] == a[i]) j++; int c = j - i; if (c >= 3) tot += c / 3; i = j; } return Math.max(tot, 3 - sum); } // 现在要讨论的是字符串的长度大于 20 的情况 int tot = 0; int[] cnts = new int[3]; // 统计 3个连续字符的个数 for (int i = 0; i < n; ) { int j = i; while (j < n && a[j] == a[i]) j++; int c = j - i; if (c >= 3) { tot += c / 3; cnts[c % 3]++; } i = j; } // 用变量 base 统计需要删除的字符个数 int base = n - 20, cur = base; for (int i = 0; i < 3; i++) { if (i == 2) cnts[i] = tot; if (cnts[i] != 0 && cur != 0) { int t = Math.min(cnts[i] * (i + 1), cur); cur -= t; tot -= t / (i + 1); } } return base + Math.max(tot, 3 - sum); } }