日照网站推广/最简短的培训心得
文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 解法
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:隐藏个人信息
出处:831. 隐藏个人信息
难度
4 级
题目描述
要求
给你一条个人信息字符串 s\texttt{s}s,它可能是一个电子邮箱,也可能是一串电话号码。
我们将通过如下规则隐藏它的隐私信息。
电子邮箱
电子邮箱的格式如下:
- 名称由大写和小写英语字母组成。
- 后面接着符号 ‘@’\texttt{`@'}‘@’。
- 后面接着由大写和小写英语字母组成的域名,域名中有一个点号 ‘.’\texttt{`.'}‘.’(点号不是第一个或最后一个字符)。
隐藏电子邮箱的做法如下:
- 名称和域名中的大写字母必须转换成小写字母;
- 名称中的中间字母(即除了第一个和最后一个字母以外的全部字母)必须由 5\texttt{5}5 个星号 "*****"\texttt{"*****"}"*****" 代替。
电话号码
电话号码的格式如下:
- 电话号码包含 10\texttt{10}10 到 13\texttt{13}13 个数字。
- 最后 10\texttt{10}10 个数字组成本地号码。
- 开头的其余 0\texttt{0}0 到 3\texttt{3}3 个数字组成国际号码。
- 分隔字符包含 {‘+’,‘-’,‘(’,‘)’,‘’}\texttt{\{`+', `-', `(', `)', ` '\}}{‘+’, ‘-’, ‘(’, ‘)’, ‘ ’},分隔数字。
隐藏电话号码的做法如下:
- 删除所有的分割字符。
- 隐藏后的电话号码的格式如下:
- 国际号码为 0\texttt{0}0 个数字时,电话号码为 "***-***-XXXX"\texttt{"***-***-XXXX"}"***-***-XXXX"。
- 国际号码为 1\texttt{1}1 个数字时,电话号码为 "+*-***-***-XXXX"\texttt{"+*-***-***-XXXX"}"+*-***-***-XXXX"。
- 国际号码为 2\texttt{2}2 个数字时,电话号码为 "+**-***-***-XXXX"\texttt{"+**-***-***-XXXX"}"+**-***-***-XXXX"。
- 国际号码为 3\texttt{3}3 个数字时,电话号码为 "+***-***-***-XXXX"\texttt{"+***-***-***-XXXX"}"+***-***-***-XXXX"。
- "XXXX"\texttt{"XXXX"}"XXXX" 是本地号码的最后 4\texttt{4}4 个数字。
示例
示例 1:
输入:s="LeetCode@LeetCode.com"\texttt{s = "LeetCode@LeetCode.com"}s = "LeetCode@LeetCode.com"
输出:"l*****e@leetcode.com"\texttt{"l*****e@leetcode.com"}"l*****e@leetcode.com"
解释:s\texttt{s}s 是电子邮箱。
名称和域名转换成小写, 名称的中间字符由 5\texttt{5}5 个星号代替。
示例 2:
输入:s="AB@qq.com"\texttt{s = "AB@qq.com"}s = "AB@qq.com"
输出:"a*****b@qq.com"\texttt{"a*****b@qq.com"}"a*****b@qq.com"
解释:s\texttt{s}s 是电子邮箱。
名称和域名转换成小写, 名称的中间字符由 5\texttt{5}5 个星号代替。
注意虽然 "ab"\texttt{"ab"}"ab" 只有 2\texttt{2}2 个字符,中间也必须有 5\texttt{5}5 个星号。
示例 3:
输入:s="1(234)567-890"\texttt{s = "1(234)567-890"}s = "1(234)567-890"
输出:"***-***-7890"\texttt{"***-***-7890"}"***-***-7890"
解释:s\texttt{s}s 是电话号码。
有 10\texttt{10}10 个数字的电话号码,所以本地号码是 10\texttt{10}10 个数字,国际号码是 0\texttt{0}0 个数字。
因此隐藏后的电话号码是 "***-***-7890"\texttt{"***-***-7890"}"***-***-7890"。
示例 4:
输入:s="86-(10)12345678"\texttt{s = "86-(10)12345678"}s = "86-(10)12345678"
输出:"+**-***-***-5678"\texttt{"+**-***-***-5678"}"+**-***-***-5678"
解释:s\texttt{s}s 是电话号码。
有 12\texttt{12}12 个数字的电话号码,所以本地号码是 10\texttt{10}10 个数字,国际号码是 2\texttt{2}2 个数字。
因此隐藏后的电话号码是 "+**-***-***-5678"\texttt{"+**-***-***-5678"}"+**-***-***-5678"。
数据范围
- s\texttt{s}s 是有效的电子邮箱或电话号码
- 如果 s\texttt{s}s 是电子邮箱:
- 8≤s.length≤40\texttt{8} \le \texttt{s.length} \le \texttt{40}8≤s.length≤40
- s\texttt{s}s 由大小写英语字母、一个 ‘@’\texttt{`@'}‘@’ 和一个 ‘.’\texttt{`.'}‘.’ 组成
- 如果 s\texttt{s}s 是电话号码:
- 10≤s.length≤20\texttt{10} \le \texttt{s.length} \le \texttt{20}10≤s.length≤20
- s\texttt{s}s 由数字、空格、‘(’\texttt{`('}‘(’、‘)’\texttt{`)'}‘)’、‘-’\texttt{`-'}‘-’ 和 ‘+’\texttt{`+'}‘+’ 组成
解法
思路和算法
对于给定的字符串 sss,需要首先判断是电子邮箱还是电话号码,然后隐藏个人信息。
由于电子邮箱一定以字母开头,电话号码不包含字母,因此可以通过 sss 的首个字符判断 sss 是电子邮箱还是电话号码,如果 sss 的首个字符是字母,则 sss 是电子邮箱,否则 sss 是电话号码。
对于电子邮箱,隐藏个人信息时需要对 ‘@’\text{`@'}‘@’ 符号前面的部分只保留第一个字母和最后一个字母,中间用 555 个星号填充,对 ‘@’\text{`@'}‘@’ 符号后面的部分保持原样,然后将隐藏个人信息之后的字符串转成小写。将 ‘@’\text{`@'}‘@’ 符号所在下标记为 atIndex\textit{atIndex}atIndex,则隐藏个人信息之后的字符串包括 sss 的首个字符、555 个星号以及 sss 的下标从 atIndex−1\textit{atIndex} - 1atIndex−1 到末尾的全部字符。由此可以得到如下实现:将 sss 的首个字符拼接到结果字符串,然后将 sss 的下标从 atIndex−1\textit{atIndex} - 1atIndex−1 到末尾的全部字符依次拼接到结果字符串,在拼接的过程中,每个字符都需要转成小写之后再拼接,这样才能确保结果字符串中的字母全部是小写字母。
对于电话号码,首先需要遍历字符串 sss 计算数字的个数,判断是本地号码还是国际号码,然后隐藏电话号码,如果数字的个数大于 101010,则是国际号码,结果字符串的第一个字符应为 ‘+’\text{`+'}‘+’。然后第二次遍历字符串 sss,当遇到非数字字符时跳过,当遇到数字时进行如下操作:
-
如果剩下的数字个数大于 444,则将一个星号拼接到结果字符串,否则将当前数字拼接到结果字符串;
-
将剩下的数字个数减 111,如果在更新剩下的数字个数之后,剩下的数字个数是 101010、777 或 444,则将 ‘–’\text{`--'}‘–’ 拼接到结果字符串。
代码
class Solution {public String maskPII(String s) {if (Character.isLetter(s.charAt(0))) {return maskEmailAddress(s);} else {return maskPhoneNumber(s);}}public String maskEmailAddress(String s) {int length = s.length();int atIndex = s.indexOf('@');StringBuffer sb = new StringBuffer();sb.append(Character.toLowerCase(s.charAt(0)));sb.append("*****");for (int i = atIndex - 1; i < length; i++) {sb.append(Character.toLowerCase(s.charAt(i)));}return sb.toString();}public String maskPhoneNumber(String s) {int count = 0;int length = s.length();for (int i = 0; i < length; i++) {char c = s.charAt(i);if (Character.isDigit(c)) {count++;}}StringBuffer sb = new StringBuffer();if (count > 10) {sb.append('+');}for (int i = 0; i < length; i++) {char c = s.charAt(i);if (Character.isDigit(c)) {if (count > 4) {sb.append('*');} else {sb.append(c);}count--;if (count == 10 || count == 7 || count == 4) {sb.append('-');}}}return sb.toString();}
}
复杂度分析
-
时间复杂度:O(n)O(n)O(n),其中 nnn 是字符串 sss 的长度。最多需要遍历字符串 sss 两次。
-
空间复杂度:O(n)O(n)O(n),其中 nnn 是字符串 sss 的长度。需要额外创建一个长度为 O(n)O(n)O(n) 的 StringBuffer\texttt{StringBuffer}StringBuffer 或 StringBuilder\texttt{StringBuilder}StringBuilder 类型的对象用于存储隐藏个人信息之后的新字符串。由于 Java 中的 String\texttt{String}String 类型的对象不可变,因此空间复杂度至少为 O(n)O(n)O(n)。