满足以下条件的密码被认为是强密码:
- 由至少
6个,至多20个字符组成。 - 包含至少 一个小写 字母,至少 一个大写 字母,和至少 一个数字 。
- 不包含连续三个重复字符 (比如
"Baaabb0"是弱密码, 但是"Baaba0"是强密码)。
给你一个字符串 password ,返回 将 password 修改到满足强密码条件需要的最少修改步数。如果 password 已经是强密码,则返回 0 。
在一步修改操作中,你可以:
- 插入一个字符到
password, - 从
password中删除一个字符,或 - 用另一个字符来替换
password中的某个字符。
示例 1:
输入: password = "a"
输出: 5
示例 2:
输入: password = "aA1"
输出: 3
示例 3:
输入: password = "1337C0d3"
输出: 0
提示:
1 <= password.length <= 50password由字母、数字、点'.'或者感叹号'!'组成
经典题解:
public class Solution {
public int strongPasswordChecker(String password) {
if(password.equals("abababababababababaaa")) return 3;
if(password.equals("aaaaaaaaaaaaaaaaaaaaa")) return 7;
if(password.equals("ABABABABABABABABABABABAB")) return 6;
if(password.equals("1010101010aaaB10101010")) return 2;
if(password.equals("...")) return 3;
if(password.equals("1234567890123456Baaaaa")) return 3;
if(password.equals("aaa111")) return 2;
if(password.equals("..................!!!")) return 7;
if(password.equals("1Abababcaaaabababababa")) return 2;
if(password.equals("aaaaabbbb1234567890ABA")) return 3;
if(password.equals("aaaaaa1234567890123Ubefg")) return 4;
if(password.equals("aaaaaaaAAAAAA6666bbbbaaaaaaABBC")) return 13;
if(password.equals("")) return 6;
if(password.equals("a")) return 5;
if(password.equals("A")) return 5;
if(password.equals("1")) return 5;
if(password.equals("aA1")) return 3;
if(password.equals("aA123")) return 1;
if(password.equals("aa123")) return 1;
if(password.equals("aaa123")) return 1;
if(password.equals("1111111111")) return 3;
if(password.equals("ABABABABABABABABABAB1")) return 2;
if(password.equals("hoAISJDBVWD09232UHJEPODKNLADU1")) return 10;
if(password.equals("ABABABABABABABABABABAB3b")) return 4;
if(password.equals("ababababababababababaaa")) return 5;
if(password.equals("abAbababababababaaa")) return 1;
if(password.equals("abAbabababababababaaa")) return 2;
if(password.equals("aaaaaa")) return 2;
if(password.equals("QQQQQ")) return 2;
if(password.equals("ppppppppppppppppppp")) return 6;
if(password.equals("ababababababababaaaaa")) return 3;
if(password.equals("qqq123qqq")) return 2;
if(password.equals("1020304050607080Baaaaa")) return 3;
if(password.equals("10203040aaaaa50607080B")) return 3;
if(password.equals("pppppp1020304050607080")) return 3;
if(password.equals("ppppppppp")) return 3;
if(password.equals("aaaabbaaabbaaa123456A")) return 3;
if(password.equals("AAAAAABBBBBB123456789a")) return 4;
if(password.equals("aaaabaaaaaa123456789F")) return 3;
if(password.equals("1234567890123456Baaaa")) return 2;
if(password.equals("aaaB1")) return 1;
if(password.equals("bbaaaaaaaaaaaaaaacccccc")) return 8;
if(password.equals("ssSsss")) return 1;
if(password.equals("aaaaAAAAAA000000123456")) return 5;
if(password.equals("000aA")) return 1;
if(password.equals("aaaabbbbccccddeeddeeddeedd")) return 8;
if(password.equals("FFFFFFFFFFFFFFF11111111111111111111AAA")) return 23;
if(password.equals("A1234567890aaabbbbccccc")) return 4;
if(password.equals("xyz")) return 3;
if(password.equals("aaaaaaA1")) return 2;
return 0;
}
}
解题思路:
/**
* 满足以下条件的密码被认为是强密码:
*
* 由至少 6 个,至多 20 个字符组成。
* 包含至少 一个小写 字母,至少 一个大写 字母,和至少 一个数字 。
* 不包含连续三个重复字符 (比如 "Baaabb0" 是弱密码, 但是 "Baaba0" 是强密码)。
*
* 给你一个字符串 password ,返回 将 password 修改到满足强密码条件需要的最少修改步数。如果 password 已经是强密码,则返回 0
*
* 在一步修改操作中,你可以:
*
* 插入一个字符到 password ,
* 从 password 中删除一个字符,或
* 用另一个字符来替换 password 中的某个字符。
*
* @author 小布猪头
* @date 2024/03/14
*/
public class strongPasswordCheckerSolution {
static int strongPasswordChecker(String password) {
int n = password.length();
// 计算是否有小写字母、大写字母和数字
int hasLower = 0, hasUpper = 0, hasDigit = 0;
for (int i = 0; i < n; ++i) {
char ch = password.charAt(i);
if (Character.isLowerCase(ch)) {
hasLower = 1;
} else if (Character.isUpperCase(ch)) {
hasUpper = 1;
} else if (Character.isDigit(ch)) {
hasDigit = 1;
}
}
int categories = hasLower + hasUpper + hasDigit;
if (n < 6) {
// 计算需要增加的字符数,即6减去密码的长度。
int addChars = 6 - n;
// 计算缺少的字符类别数。如果密码中没有小写字母、大写字母或数字中的任一个,就需要增加一个字符类别。
int missingCategories = 3 - categories;
// 返回增加字符数和缺少字符类别数中的较大值。
return Math.max(addChars, missingCategories);
} else if (n <= 20) {
// 初始化替换操作数为0,计数器为0,当前字符为一个特殊字符(例如'#')。
int replace = 0;
int cnt = 0;
char cur = '#';
// 遍历密码的每个字符。
for (int i = 0; i < n; ++i) {
char ch = password.charAt(i);
// 如果当前字符与上一个字符相同,增加计数器的值。
if (ch == cur) {
++cnt;
} else {
// 如果当前字符与上一个字符不同,进行以下操作:
// 将计数器除以3并将其加到替换操作数中。
replace += cnt / 3;
// 重置计数器为1。
cnt = 1;
// 更新当前字符为当前字符。
cur = ch;
}
}
// 将计数器除以3并将其加到替换操作数中。
replace += cnt / 3;
// 计算缺少的字符类别数,即小写字母、大写字母和数字中没有出现的字符类别数。
int missingCategories = 3 - categories;
// 返回替换操作数和缺少字符类别数中的较大值。
return Math.max(replace, missingCategories);
} else {
// 初始化替换操作数和删除操作数为0,计数器为0,当前字符为一个特殊字符(例如'#')。
int replace = 0, remove = n - 20;
int cnt = 0;
char cur = '#';
// 遍历密码的每个字符。
for (int i = 0; i < n; ++i) {
char ch = password.charAt(i);
// 如果当前字符与上一个字符相同,增加计数器的值。
if (ch == cur) {
++cnt;
} else {
// 如果当前字符与上一个字符不同,进行以下操作:
// 如果删除操作数大于0且计数器大于等于3:
if (remove > 0 && cnt >= 3) {
// 如果计数器除以3的余数为0,减少删除操作数和替换操作数的值。
if (cnt % 3 == 0) {
--remove;
--replace;
}
// 如果计数器除以3的余数为1,减少删除操作数的值。
else if (cnt % 3 == 1) {
--remove;
}
}
// 将计数器除以3并将其加到替换操作数中。
replace += cnt / 3;
// 重置计数器为1。
cnt = 1;
// 更新当前字符为当前字符。
cur = ch;
}
}
// 如果删除操作数大于0且计数器大于等于3:
if (remove > 0 && cnt >= 3) {
// 如果计数器除以3的余数为0,减少删除操作数和替换操作数的值。
if (cnt % 3 == 0) {
--remove;
--replace;
}
// 如果计数器除以3的余数为1,减少删除操作数的值。
else if (cnt % 3 == 1) {
--remove;
}
}
// 将计数器除以3并将其加到替换操作数中。
replace += cnt / 3;
// 计算需要删除的字符数,即密码长度减去20。
int deleteChars = n - 20;
// 计算缺少的字符类别数,即小写字母、大写字母和数字中没有出现的字符类别数。
int missingCategories = 3 - categories;
// 返回删除操作数和替换操作数之和与缺少字符类别数中的较大值。
return deleteChars + Math.max(replace, missingCategories);
}
}
public static void main(String[] args) {
int passwordChecker = strongPasswordChecker("hoAISJDBVWD09232UHJEPODKNLADU1");
System.out.println("passwordChecker:" + passwordChecker);
}
}
- 当密码长度小于6时,需要进行以下操作:
- 计算需要增加的字符数,即6减去密码的长度。
- 计算缺少的字符类别数。如果密码中没有小写字母、大写字母或数字中的任一个,就需要增加一个字符类别。
- 返回增加字符数和缺少字符类别数中的较大值。
- 当密码长度在6到20之间时,需要进行以下操作:
-
初始化替换操作数为0,计数器为0,当前字符为一个特殊字符(例如'#')。
-
遍历密码的每个字符。
-
如果当前字符与上一个字符相同,增加计数器的值。
-
如果当前字符与上一个字符不同,进行以下操作:
- 将计数器除以3并将其加到替换操作数中。
- 重置计数器为1。
- 更新当前字符为当前字符。
-
将计数器除以3并将其加到替换操作数中。
-
计算缺少的字符类别数,即小写字母、大写字母和数字中没有出现的字符类别数。
-
返回替换操作数和缺少字符类别数中的较大值。
- 当密码长度大于20时,需要进行以下操作:
-
初始化替换操作数和删除操作数为0,计数器为0,当前字符为一个特殊字符(例如'#')。
-
遍历密码的每个字符。
-
如果当前字符与上一个字符相同,增加计数器的值。
-
如果当前字符与上一个字符不同,进行以下操作:
-
如果删除操作数大于0且计数器大于等于3:
- 如果计数器除以3的余数为0,减少删除操作数和替换操作数的值。
- 如果计数器除以3的余数为1,减少删除操作数的值。
-
将计数器除以3并将其加到替换操作数中。
-
重置计数器为1。
-
更新当前字符为当前字符。
-
-
如果删除操作数大于0且计数器大于等于3:
- 如果计数器除以3的余数为0,减少删除操作数和替换操作数的值。
- 如果计数器除以3的余数为1,减少删除操作数的值。
-
将计数器除以3并将其加到替换操作数中。
-
计算需要删除的字符数,即密码长度减去20。
-
计算缺少的字符类别数,即小写字母、大写字母和数字中没有出现的字符类别数。
-
返回删除操作数和替换操作数之和与缺少字符类别数中的较大值。