题目链接:https://leetcode-cn.com/problems/strong-password-checker/
题意
一个强密码应满足以下所有条件:
1.由至少6个,至多20个字符组成。
2.至少包含一个小写字母,一个大写字母,和一个数字。
3.同一字符不能连续出现三次 (比如 “…aaa…” 是不允许的, 但是 “…aa…a…” 是可以的)。
求要将 s 修改为满足强密码条件的字符串所需要进行修改的最小步数。
修改包括删除、替换和增加一个字符
题解
设缺失类型数目为
c
n
cn
cn
当
n
<
6
n<6
n<6时,答案为
m
a
x
(
c
n
,
6
−
n
)
max(cn,6-n)
max(cn,6−n),因为必须增加
6
−
n
6-n
6−n个字符,最多只有5个字符肯定可以清除重复
当
n
≤
20
n\leq 20
n≤20时,考虑所有连续相同的,长度为
c
n
t
cnt
cnt,则通过替换消除需要
c
n
t
/
3
cnt/3
cnt/3,通过插入和删除的代价更高,最后答案为
m
a
x
(
c
n
,
∑
c
n
t
/
3
)
max(cn,\sum cnt/3)
max(cn,∑cnt/3)
当
n
>
20
n>20
n>20时,至少要删除
n
−
20
n-20
n−20个字符,考虑删除使得重复项减少,发现重复项删除的时候按照
c
n
t
%
3
cnt\%3
cnt%3的值有不同的代价,优先删除代价小的即可,删除到20个字符以后如果仍然有重复那么就通过替换处理,开路剩余的cnt集合,答案为
n
−
20
+
m
a
x
(
c
n
,
∑
c
n
t
/
3
)
n-20+max(cn,\sum cnt/3)
n−20+max(cn,∑cnt/3)
时间复杂度
O
(
n
)
O(n)
O(n),空间复杂度
O
(
1
)
O(1)
O(1)
code
#define ms(a) memset(a, 0, sizeof(a))
int gettype(char ch)
{
if (ch >= '0' && ch <= '9')
return 1;
if (ch >= 'A' && ch <= 'Z')
return 2;
if (ch >= 'a' && ch <= 'z')
return 3;
return 0;
}
class Solution
{
public:
int strongPasswordChecker(string password)
{
int n = password.length();
int visn[4];
ms(visn);
for (int i = 0; i < n; i++)
visn[gettype(password[i])] = 1;
int cn = 0;
for (int i = 1; i <= 3; i++)
if (!visn[i])
cn++;
if (n < 6)
return max(cn, 6 - n);
if (n <= 20)
{
int cnt = 1;
int ans = 0;
for (int i = 1; i < n; i++)
{
if (password[i] != password[i - 1])
{
ans += cnt / 3;
cnt = 1;
}
else
cnt++;
}
ans += cnt / 3;
return max(cn, ans);
}
vector<int> cnt;
int tmp = 1;
int dn = n - 20;
for (int i = 1; i < n; i++)
{
if (password[i] != password[i - 1])
{
if (tmp >= 3)
cnt.push_back(tmp);
tmp = 1;
}
else
tmp++;
}
if (tmp >= 3)
cnt.push_back(tmp);
int ctm[3];
ms(ctm);
for (int i = 0; i < cnt.size(); i++)
{
ctm[cnt[i] % 3]++;
ctm[2] += cnt[i] / 3 - 1;
}
for (int i = 0; i < 3; i++)
{
int dt = i + 1;
if (dn >= dt * ctm[i])
{
dn -= dt * ctm[i];
ctm[i] = 0;
}
else
{
ctm[i] -= dn / dt;
dn %= dt;
}
}
tmp = 0;
for (int i = 0; i < 3; i++)
tmp += ctm[i];
return n - 20 + max(cn, tmp);
}
};