题目概述
如果一个密码满足下述所有条件,则认为这个密码是强密码:
- 由至少 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 由字母、数字、点 '.' 或者感叹号 '!'
题目来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/strong-password-checker
解题分析
方法:模拟
本题无非三种情况,根据字符串长度进行模拟,我们令长度为 len:
- len < 6 时,我们需要进行的操作显然只有添加,影响添加的因素只有大小写字母和数字是否出现,我们可以先遍历记录这三种种类的个数,令为 category,那么我们需要添加的个数就是 6 - len 和 3 - category 的最大值。
- 6 <= len <= 20,我们需要进行的操作显然只有替换,因此我们只需要记录连续相同字符出现的个数,然后将它的每三个字符替换为其他字符即可,即相同个数整除 3,即替换的次数,最后和 3 - category 进行比较返回最大值即可。
- len > 20 时,我们需要进行的操作分为删除和替换,而替换操作可以用删除操作来代替,比如出现 3 个相同字符,删除一个和替换一个一样,可以省去操作次数,因此我们可以利用一个数组来记录连续相同字符出现次数除以3的余数的个数,再对这些余数进行操作,记录可以省去的最大值,然后将省去后的次数加上删除的次数和 3 - category 比较返回最大值即可。
时间复杂度:O(n) n 为字符串长度
空间复杂度:O(n) 将字符串转化为字符数组为 O(n),直接在原字符串上操作就是 O(1)
class Solution {
public int strongPasswordChecker(String password) {
//字符数组
char[] cs = password.toCharArray();
//字符串长度
int len = cs.length;
//记录大小写字母和数字的数量
int upper = 0, lower = 0, num = 0;
//遍历
for(char c: cs){
if(c >= 'A' && c <= 'Z'){
upper = 1;
}
else if(c >= 'a' && c <= 'z'){
lower = 1;
}else if(c >= '0' && c <= '9'){
num = 1;
}
}
//记录没有的字符种类
int category = 3 - upper - lower - num;
//字符串长度小于6
if(len < 6){
return Math.max(6 - len, category);
}
//记录修改次数
int update = 0;
//记录取余3之后的数的数量
int[] nums = new int[3];
//遍历寻找连续出现三次以上字符
for(int i = 0; i < len-1; ++i){
//记录相同字符数量
int same = 1;
while(i < len-1 && cs[i] == cs[i+1]){
same++;
++i;
}
if(same > 2){
update += same / 3;
nums[same % 3]++;
}
}
//字符串长度在范围内
if(len <= 20){
return Math.max(update, category);
}
//长度大于20
//定义要删除的次数
int del = len - 20, cur = del;
//根据余数进行遍历
for(int i = 0; i < 3; ++i){
if(i == 2){
nums[i] = update;
}
if(cur > 0){
int temp = Math.min(nums[i] * (i + 1), cur);
cur -= temp;
update -= temp / (i+1);
}
}
return del + Math.max(update, category);
}
}