字符串题目:隐藏个人信息

文章目录

题目

标题和出处

标题:隐藏个人信息

出处: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{`+'} ‘+’ 组成

解法

思路和算法

对于给定的字符串 s s s,需要首先判断是电子邮箱还是电话号码,然后隐藏个人信息。

由于电子邮箱一定以字母开头,电话号码不包含字母,因此可以通过 s s s 的首个字符判断 s s s 是电子邮箱还是电话号码,如果 s s s 的首个字符是字母,则 s s s 是电子邮箱,否则 s s s 是电话号码。

对于电子邮箱,隐藏个人信息时需要对 ‘@’ \text{`@'} ‘@’ 符号前面的部分只保留第一个字母和最后一个字母,中间用 5 5 5 个星号填充,对 ‘@’ \text{`@'} ‘@’ 符号前面的部分保持原样,然后将隐藏个人信息之后的字符串转成小写。将 ‘@’ \text{`@'} ‘@’ 符号所在下标记为 atIndex \textit{atIndex} atIndex,则隐藏个人信息之后的字符串包括 s s s 的首个字符、 5 5 5 个星号以及 s s s 的下标从 atIndex − 1 \textit{atIndex} - 1 atIndex−1 到末尾的全部字符。由此可以得到如下实现:将 s s s 的首个字符拼接到结果字符串,然后将 s s s 的下标从 atIndex − 1 \textit{atIndex} - 1 atIndex−1 到末尾的全部字符依次拼接到结果字符串,在拼接的过程中,每个字符都需要转成小写之后再拼接,这样才能确保结果字符串中的字母全部是小写字母。

对于电话号码,首先需要遍历字符串 s s s 计算数字的个数,判断是本地号码还是国际号码,然后隐藏电话号码,如果数字的个数大于 10 10 10,则是国际号码,结果字符串的第一个字符应为 ‘+’ \text{`+'} ‘+’。然后第二次遍历字符串 s s s,当遇到非数字字符时跳过,当遇到数字时进行如下操作:

  1. 如果剩下的数字个数大于 4 4 4,则将一个星号拼接到结果字符串,否则将当前数字拼接到结果字符串;

  2. 将剩下的数字个数减 1 1 1,如果在更新剩下的数字个数之后,剩下的数字个数是 10 10 10、 7 7 7 或 4 4 4,则将 ‘–’ \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),其中 n n n 是字符串 s s s 的长度。最多需要遍历字符串 s s s 两次。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 s s s 的长度。需要额外创建一个长度为 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)。

上一篇:UVA620 Cellular Structure 题解


下一篇:更改系统字体大小、显示大小、默认dpi