题目
420.强密码检验器
题目大意
如果一个密码满足下述所有条件,则认为这个密码是强密码:
- 由至少
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
由字母、数字、点'.'
或者感叹号'!'
思路
考虑三种情况:
- 字符串
password
长度 < 6 <6 <6 - 字符串
password
长度 ∈ [ 6 , 20 ] \in[6,20] ∈[6,20] - 字符串
password
长度 > 20 >20 >20
有三种操作:
- 添加一个字符
- 替换一个字符
- 删除一个字符
设定low
表示是否有小写字母(有小写字母low=1
);upp
表示是否有大写字母(有大写字母upp=1
);num
表示是否有数字(有数字num=1
)。
设cnt
为当前连续相同的字母(初始为
1
1
1),cur
为当前字符,rep
表示需要替换的字符数量(我们认为每连续三个就要替换一个字符,即
r
e
p
=
⌊
c
n
t
/
3
⌋
rep=\lfloor cnt/3 \rfloor
rep=⌊cnt/3⌋),remove
表示多余需要删除的字符数量,
k
[
i
]
k[i]
k[i]表示
c
n
t
%
3
cnt\%3
cnt%3的的总数。
下面对三种情况讨论:
-
对于字符串
password
长度 < 6 <6 <6:很显然删除一个字符没意义,还不如替换一个字符,而替换一个字符是为了防止连续三个重复字母,那完全可以每两个之间添加一个其余字符来防止连续三个重复字母。所以答案就是max(3-(num+low+upp),6-len)
-
字符串
password
长度 ∈ [ 6 , 20 ] \in[6,20] ∈[6,20]:添加一个字符和删除一个字符意义不大,不如直接替换一个字符,因为同一字符不连续出现 3 3 3次,所以对于连续的 c n t cnt cnt个相同的字符,可以替换其中 ⌊ c n t / 3 ⌋ \lfloor cnt/3 \rfloor ⌊cnt/3⌋(每满三个替换末尾一个),并且必须保证大写字母、小写字母、数字都有,所以最后答案就是 m a x ( 3 − ( n u m + l o w + u p p ) , r e p ) max(3-(num+low+upp),rep) max(3−(num+low+upp),rep)。 -
字符串
password
长度 > 20 >20 >20:添加一个字符意义不大,因为数字已经过多了,所以删除一个字符和替换一个字符比较有用。首先可以分别求出替换一个字符和删除一个字符需要的次数。- 替换一个字符的次数: ∑ ( ⌊ c n t / 3 ⌋ ) \sum(\lfloor cnt/3 \rfloor) ∑(⌊cnt/3⌋)
- 删除一个字符的次数: l e n − 20 len-20 len−20
但是在删除字符的过程中,连续相同的字符数量也会变少。根据 c n t % 3 cnt\%3 cnt%3的值分为三种情况:
- c n t % 3 = = 0 cnt\%3==0 cnt%3==0:那么删除 1 1 1个字符后, ⌊ c n t / 3 ⌋ \lfloor cnt/3 \rfloor ⌊cnt/3⌋的值减 1 1 1,之后每删除 3 3 3个字符, ⌊ c n t / 3 ⌋ \lfloor cnt/3 \rfloor ⌊cnt/3⌋的值减 1 1 1。
- c n t % 3 = = 1 cnt\%3==1 cnt%3==1:那么删除 2 2 2个字符后, ⌊ c n t / 3 ⌋ \lfloor cnt/3 \rfloor ⌊cnt/3⌋的值减 1 1 1,之后每删除 3 3 3个字符, ⌊ c n t / 3 ⌋ \lfloor cnt/3 \rfloor ⌊cnt/3⌋的值减 1 1 1。
- c n t % 3 = = 2 cnt\%3==2 cnt%3==2:那么删除 3 3 3个字符后, ⌊ c n t / 3 ⌋ \lfloor cnt/3 \rfloor ⌊cnt/3⌋的值减 1 1 1,之后每删除 3 3 3个字符, ⌊ c n t / 3 ⌋ \lfloor cnt/3 \rfloor ⌊cnt/3⌋的值减 1 1 1。
因此在删除字符时,优先从所有 c n t % 3 = = 0 cnt\%3==0 cnt%3==0的连续相同字符中删除 1 1 1个字符,然后再删除 c n t % 3 = = 1 cnt\%3==1 cnt%3==1的连续字符中删除 2 2 2个,最后删除 3 3 3个字符的。最后答案为 ( l e n − 20 ) + m a x ( r e p , 3 − ( n u m + l o w + u p p ) ) (len-20)+max(rep,3-(num+low+upp)) (len−20)+max(rep,3−(num+low+upp))。
代码
// short int long float double bool char string void
// array vector stack queue auto const operator
// class public private static friend extern
// sizeof new delete return cout cin memset malloc
// relloc size length memset malloc relloc size length
// for while if else switch case continue break system
// endl reverse sort swap substr begin end iterator
// namespace include define NULL nullptr exit equals
// index col row arr err left right ans res vec que sta
// state flag ch str max min default charray std
// maxn minn INT_MAX INT_MIN push_back insert
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>PII;
typedef pair<int, string>PIS;
const int maxn=5e4+50;//注意修改大小
long long read(){long long x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}while(isdigit(c)){x=x*10+c-'0';c=getchar();}return x*f;}
ll qpow(ll x,ll q,ll Mod){ll ans=1;while(q){if(q&1)ans=ans*x%Mod;q>>=1;x=(x*x)%Mod;}return ans%Mod;}
class Solution {
public:
int strongPasswordChecker(string password) {
int len=password.length();
vector<int>k(5);
int low=0,upp=0,num=0;
for(auto it:password){
if(isdigit(it)){
num=1;
}
if(islower(it)){
low=1;
}
if(isupper(it)){
upp=1;
}
}
if(len<6){
return max(3-(num+low+upp),6-len);
}
else if(len<=20){
int cnt=1;
char cur='#';
int rep=0;
for(auto it:password){
if(it==cur){
cnt++;
}
else{
rep+=cnt/3;
cnt=1;
cur=it;
}
}
rep+=cnt/3;
return max(rep,3-(num+low+upp));
}
else{
int cnt=1,remove=len-20,rep=0;
char cur='#';
for(auto it:password){
if(it==cur){
cnt++;
}
else{
if(remove>0&&cnt>=3){
if(cnt%3==0){
remove--;
rep--;
}
else if(cnt%3==1){
k[1]++;
}
}
rep+=cnt/3;
cnt=1;
cur=it;
}
}
if (remove > 0 && cnt >= 3){
if (cnt % 3 == 0){
remove--;
rep--;
}
else if (cnt % 3 == 1){
k[1]++;
}
}
rep += cnt / 3;
int use2=min({rep,k[1],remove/2});
rep -= use2;
remove -= use2*2;
int use3=min({rep,remove/3});
rep -= use3;
remove -= use3*3;
return (len-20)+max(rep,3-(num+low+upp));
}
}
};