420.强密码检验器

题目

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 len20

    但是在删除字符的过程中,连续相同的字符数量也会变少。根据 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)) (len20)+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));
		}
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Phoenix_ZengHao

创作不易,能否打赏一瓶饮料?

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值