420:强密码检验器

This commit is contained in:
轩辕龙儿 2022-04-02 16:40:19 +08:00
parent 4c4e8f6414
commit f20ce032ff
2 changed files with 192 additions and 0 deletions

View File

@ -0,0 +1,141 @@
//
//如果一个密码满足下述所有条件则认为这个密码是强密码
//
//
// 由至少 6 至多 20 个字符组成
// 至少包含 一个小写 字母一个大写 字母 一个数字
// 同一字符 不能 连续出现三次 (比如 "...aaa..." 是不允许的, 但是 "...aa...a..." 如果满足其他条件也可以算是强密码)
//
//
// 给你一个字符串 password 返回 password 修改到满足强密码条件需要的最少修改步数如果 password 已经是强密码则返回 0
//
//
// 在一步修改操作中你可以
//
//
// 插入一个字符到 password
// password 中删除一个字符
// 用另一个字符来替换 password 中的某个字符
//
//
//
//
// 示例 1
//
//
//输入password = "a"
//输出5
//
//
// 示例 2
//
//
//输入password = "aA1"
//输出3
//
//
// 示例 3
//
//
//输入password = "1337C0d3"
//输出0
//
//
//
//
// 提示
//
//
// 1 <= password.length <= 50
// password 由字母数字 '.' 或者感叹号 '!'
//
// Related Topics 贪心 字符串 优先队列 👍 138 👎 0
package leetcode.editor.cn;
//420:强密码检验器
public class StrongPasswordChecker {
public static void main(String[] args) {
Solution solution = new StrongPasswordChecker().new Solution();
// TO TEST
solution.strongPasswordChecker("aaa111");
}
//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
public int strongPasswordChecker(String password) {
char[] cs = password.toCharArray();
int n = cs.length;
// 计算字符种类
int A = 0, B = 0, C = 0;
for (char c : cs) {
if (c >= 'a' && c <= 'z') {
A = 1;
} else if (c >= '0' && c <= '9') {
B = 1;
} else if (c >= 'A' && c <= 'Z') {
C = 1;
}
}
int m = A + B + C;
// 情况1
if (n < 6) {
return Math.max(6 - n, 3 - m);
}
// 情况2
else if (n <= 20) {
// 需要替换的次数
int tot = 0;
// 采用双指针的方式求出超三连字符
for (int i = 0; i < n; ) {
int j = i;
while (j < n && cs[j] == cs[i]) {
j++;
}
int l = j - i;
if (l >= 3) {
tot += l / 3;
}
i = j;
}
return Math.max(tot, 3 - m);
} else {
int tot = 0;
int[] counts = new int[3];
for (int i = 0; i < n; ) {
int j = i;
while (j < n && cs[j] == cs[i]) {
j++;
}
int l = j - i;
// 同时统计 需要替换的次数 l%3
if (l >= 3) {
tot += l / 3;
counts[l % 3]++;
}
i = j;
}
// base不管怎么样都要删这么多次
int base = n - 20, cur = base;
for (int i = 0; i < 3; i++) {
// l%3==2 的情况因为l%3==0和l%3==0的情况在删去只会就会变成l%3==2同时每改一次等价于删除3次所以替代
if (i == 2) {
counts[i] = tot;
}
if (counts[i] != 0 && cur != 0) {
// 对于 l%3==i 的数来说 要删的个数就是 counts[i] * (i + 1)
int t = Math.min(counts[i] * (i + 1), cur);
cur -= t;
// 每减少一个删去一个 i+1 都可以少修改一次
tot -= t / (i + 1);
}
}
return base + Math.max(tot, 3 - m);
}
}
}
//leetcode submit region end(Prohibit modification and deletion)
}

View File

@ -0,0 +1,51 @@
<p>&nbsp;</p>
如果一个密码满足下述所有条件,则认为这个密码是强密码:
<ul>
<li>由至少 <code>6</code> 个,至多 <code>20</code> 个字符组成。</li>
<li>至少包含 <strong>一个小写 </strong>字母,<strong>一个大写</strong> 字母,和 <strong>一个数字</strong></li>
<li>同一字符 <strong>不能 </strong>连续出现三次 (比如 <code>"...aaa..."</code> 是不允许的, 但是&nbsp;<code>"...aa...a..."</code> 如果满足其他条件也可以算是强密码)。</li>
</ul>
<p>给你一个字符串 <code>password</code> ,返回&nbsp;<em><code>password</code> 修改到满足强密码条件需要的最少修改步数。如果 <code>password</code> 已经是强密码,则返回 <code>0</code></em></p>
<p>在一步修改操作中,你可以:</p>
<ul>
<li>插入一个字符到 <code>password</code> </li>
<li><code>password</code> 中删除一个字符,或</li>
<li>用另一个字符来替换 <code>password</code> 中的某个字符。</li>
</ul>
<p>&nbsp;</p>
<p><strong>示例 1</strong></p>
<pre>
<strong>输入:</strong>password = "a"
<strong>输出:</strong>5
</pre>
<p><strong>示例 2</strong></p>
<pre>
<strong>输入:</strong>password = "aA1"
<strong>输出:</strong>3
</pre>
<p><strong>示例 3</strong></p>
<pre>
<strong>输入:</strong>password = "1337C0d3"
<strong>输出:</strong>0
</pre>
<p>&nbsp;</p>
<p><strong>提示:</strong></p>
<ul>
<li><code>1 &lt;= password.length &lt;= 50</code></li>
<li><code>password</code> 由字母、数字、点 <code>'.'</code> 或者感叹号 <code>'!'</code></li>
</ul>
<div><div>Related Topics</div><div><li>贪心</li><li>字符串</li><li>堆(优先队列)</li></div></div><br><div><li>👍 138</li><li>👎 0</li></div>