Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

831. Masking Personal Information - Leetcode Solution

Problem Description

The "Masking Personal Information" problem requires you to write a function that takes a string s representing either an email address or a phone number and returns the masked version of that personal information.

  • If s is an email address:
    • Mask it so that only the first and last character of the name are visible, all other letters in the name are replaced with 5 asterisks ('*').
    • The name is case-insensitive and should be converted to lowercase, as should the entire email.
    • The domain part (after '@') should remain unchanged except for being lowercased.
  • If s is a phone number:
    • Remove all non-digit characters.
    • The last 10 digits are the local number. Any digits before that form the country code.
    • Format the masked number as ***-***-XXXX for local numbers, or +**-***-***-XXXX etc. for numbers with a country code, where X are the last 4 digits.

The function must handle both formats, and return the correctly masked version based on the input.

Thought Process

The first step is to distinguish between an email and a phone number. Since emails always contain an @, we can use this to decide how to process the input.

  • For an email, we split at @, lowercase everything, and mask the name part except for the first and last character.
  • For a phone number, we extract all digits, then determine the country code (if any) and format the result accordingly.

The brute-force approach would be to check every possible masking, but since the requirements are clear and deterministic, we can directly apply the masking rules. This avoids unnecessary computations and makes for a concise solution.

Solution Approach

  • Step 1: Input Type Detection
    • If the string contains an @, treat it as an email. Otherwise, treat it as a phone number.
  • Step 2: Email Masking
    • Convert the string to lowercase.
    • Split the string into name and domain parts at @.
    • Take the first and last character of the name. Replace all characters in between with five asterisks ('*').
    • Concatenate the masked name, @, and domain.
  • Step 3: Phone Number Masking
    • Remove all non-digit characters to get only the digits.
    • The last 10 digits are the local number. Any digits before that are the country code.
    • Format:
      • If there is no country code: ***-***-XXXX
      • If there is a country code: +**-***-***-XXXX (where ** is replaced by the appropriate number of asterisks for the country code length)
  • Step 4: Return the Masked String

This approach ensures that both email and phone number masking are handled efficiently and according to the problem's requirements.

Example Walkthrough

Let's consider two examples:

  • Email Example:
    Input: "LeetCode@LeetCode.com"
    • Lowercase: "leetcode@leetcode.com"
    • Name part: "leetcode"; Domain: "leetcode.com"
    • First and last character: 'l' and 'e'
    • Masked: "l*****e@leetcode.com"
  • Phone Number Example:
    Input: "86-(10)12345678"
    • Extract digits: "861012345678"
    • Country code: "86" (first 2 digits), local number: "1012345678"
    • Format: "+**-***-***-5678"

The function correctly identifies the type and applies the required masking.

Time and Space Complexity

  • Brute-force Approach:
    • Not applicable here, as the problem is deterministic and does not require searching or checking multiple possibilities.
  • Optimized Approach:
    • Time Complexity: O(N), where N is the length of the input string. We scan the string once for digits or lowercasing.
    • Space Complexity: O(N), for storing the lowercased string and the digits (in the phone number case).

Summary

The solution to the "Masking Personal Information" problem is straightforward due to the clear rules for emails and phone numbers. By first identifying the input type, then applying deterministic masking logic, we avoid brute-force solutions and ensure efficiency. The use of string manipulation and regular expressions (for digits) makes the solution both concise and effective.

Code Implementation

class Solution:
    def maskPII(self, s: str) -> str:
        s = s.strip()
        if '@' in s:
            name, domain = s.split('@')
            name = name.lower()
            domain = domain.lower()
            masked = name[0] + '*****' + name[-1] + '@' + domain
            return masked
        else:
            digits = [c for c in s if c.isdigit()]
            local = ''.join(digits[-10:])
            country = digits[:-10]
            masked_local = "***-***-" + local[-4:]
            if not country:
                return masked_local
            else:
                return "+" + "*" * len(country) + "-" + masked_local
      
class Solution {
public:
    string maskPII(string s) {
        if (s.find('@') != string::npos) {
            // Email
            transform(s.begin(), s.end(), s.begin(), ::tolower);
            int at = s.find('@');
            string name = s.substr(0, at);
            string domain = s.substr(at);
            string masked = string(1, name[0]) + "*****" + string(1, name.back()) + domain;
            return masked;
        } else {
            // Phone
            string digits;
            for (char c : s) {
                if (isdigit(c)) digits += c;
            }
            string local = digits.substr(digits.size() - 10);
            string masked_local = "***-***-" + local.substr(6, 4);
            if (digits.size() == 10) {
                return masked_local;
            } else {
                string country = "+" + string(digits.size() - 10, '*') + "-";
                return country + masked_local;
            }
        }
    }
};
      
class Solution {
    public String maskPII(String s) {
        s = s.trim();
        if (s.contains("@")) {
            String[] parts = s.split("@");
            String name = parts[0].toLowerCase();
            String domain = parts[1].toLowerCase();
            return name.charAt(0) + "*****" + name.charAt(name.length() - 1) + "@" + domain;
        } else {
            StringBuilder digits = new StringBuilder();
            for (char c : s.toCharArray()) {
                if (Character.isDigit(c)) digits.append(c);
            }
            String d = digits.toString();
            String local = d.substring(d.length() - 10);
            String maskedLocal = "***-***-" + local.substring(6);
            if (d.length() == 10) {
                return maskedLocal;
            } else {
                String country = "+" + "*".repeat(d.length() - 10) + "-";
                return country + maskedLocal;
            }
        }
    }
}
      
var maskPII = function(s) {
    s = s.trim();
    if (s.indexOf('@') !== -1) {
        let [name, domain] = s.split('@');
        name = name.toLowerCase();
        domain = domain.toLowerCase();
        return name[0] + '*****' + name[name.length - 1] + '@' + domain;
    } else {
        let digits = s.replace(/\D/g, '');
        let local = digits.slice(-10);
        let country = digits.slice(0, -10);
        let maskedLocal = "***-***-" + local.slice(-4);
        if (country.length === 0) {
            return maskedLocal;
        } else {
            return "+" + "*".repeat(country.length) + "-" + maskedLocal;
        }
    }
};