Facebook Pixel

3491. Phone Number Prefix πŸ”’

Problem Description

You are given a string array numbers that represents phone numbers. The task is to determine if no phone number is a prefix of any other phone number in the array. If no such prefix relationship exists, return true. Otherwise, return false.

Intuition

The solution to the problem involves sorting and prefix checking. The goal is to ensure that no phone number acts as a prefix for another number within the array. We begin by sorting the numbers array by the length of the strings, which allows us to compare shorter numbers first with potential candidates.

For each phone number s in the array, we check all previous entries t (which are shorter due to sorting) to see if t is a prefix of s. If such a prefix t is found, it means there's a phone number that is a prefix of another, and we return false. If the loop completes without finding any prefix relations, then we return true, indicating that no prefix relationships exist.

Learn more about Trie and Sorting patterns.

Solution Approach

The reference solution employs a combination of sorting and prefix checking to solve the problem efficiently. Here's how the solution works:

  1. Sorting by Length:

    • The array numbers is sorted based on the length of the phone numbers. This ensures that when we check prefixes, shorter numbers (which are more likely to be prefixes) are evaluated first.
    numbers.sort(key=len)
  2. Iterate and Check Prefixes:

    • For each phone number s in the sorted array, we examine all preceding numbers t. Since the array is sorted by length, these preceding numbers will all be shorter or equal in length to s.
    • For each s, we utilize the startswith method to see if any preceding number t is a prefix of s.
    • If such a prefix relationship is found (s.startswith(t)), we return false immediately, indicating that a prefix conflict exists.
    for i, s in enumerate(numbers):
        if any(s.startswith(t) for t in numbers[:i]):
            return False
  3. Return Result:

    • If the loop completes without identifying any prefixes, return true. This signifies that no phone number in the list is a prefix of any other phone number.
    return True

By leveraging sorting and prefix checking within this structured approach, the solution efficiently determines whether any phone number is a prefix of another. The time complexity is mainly influenced by the sorting step, and the prefix checking ensures accuracy within the sorted list.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's consider a small example to illustrate the solution approach. Suppose we have the following array of phone numbers:

numbers = ["123", "45", "1234", "567"]

Our task is to determine if any phone number in the list is a prefix of another number. Follow these steps:

  1. Sorting by Length:
    We begin by sorting the array by the length of its contents, so the resulting array becomes:

    numbers = ["45", "123", "567", "1234"]

    This arrangement helps in easily identifying potential prefixes since shorter numbers are more likely to be prefixes.

  2. Iterate and Check Prefixes:

    • Start iterating through the sorted list. For each number s in the list, check all preceding numbers t. Use the startswith method to determine if any t is a prefix of s.
    • For "45", there are no preceding numbers, so no prefix check is needed.
    • For "123", the preceding number is "45", which is not a prefix of "123".
    • For "567", the preceding numbers are "45" and "123", neither of which is a prefix of "567".
    • Finally, for "1234", check against "45", "123", and "567". Here, "123" is indeed a prefix of "1234".

    Detected the prefix situation, so we immediately return False.

  3. Return Result: The loop identified a prefix relationship, so the function returns False, indicating that a prefix conflict exists in the list.

By using sorting and prefix checking, the method efficiently determines the presence of any prefix relationships among the numbers in the array.

Solution Implementation

1from typing import List
2
3class Solution:
4    def phonePrefix(self, numbers: List[str]) -> bool:
5        # Sort the list of numbers by their length
6        numbers.sort(key=len)
7      
8        # Iterate over each number in the sorted list
9        for i, s in enumerate(numbers):
10            # Check if any shorter or equal-length number is a prefix of the current number
11            if any(s.startswith(t) for t in numbers[:i]):
12                # If a prefix match is found, return False
13                return False
14      
15        # If no prefix matches were found, return True
16        return True
17
1// Import required packages
2import java.util.Arrays;
3
4class Solution {
5    // Method to check if one phone number is a prefix of any other phone number in the list
6    public boolean phonePrefix(String[] numbers) {
7        // Sort the array of numbers based on the length of each phone number
8        Arrays.sort(numbers, (a, b) -> Integer.compare(a.length(), b.length()));
9      
10        // Iterate over each phone number in the sorted array
11        for (int i = 0; i < numbers.length; i++) {
12            String currentNumber = numbers[i];
13          
14            // Check if the current number starts with any of the previous numbers
15            for (int j = 0; j < i; j++) {
16                // If current number starts with a previous number, return false
17                if (currentNumber.startsWith(numbers[j])) {
18                    return false;
19                }
20            }
21        }
22      
23        // If no number is a prefix of another number, return true
24        return true;
25    }
26}
27
1#include <algorithm>
2#include <vector>
3#include <string>
4
5using namespace std;
6
7class Solution {
8public:
9    bool phonePrefix(vector<string>& numbers) {
10        // Sort the numbers based on their length in ascending order
11        sort(numbers.begin(), numbers.end(), [](const string& a, const string& b) {
12            return a.size() < b.size();
13        });
14
15        // Check if any smaller number is a prefix of a larger number
16        for (int i = 0; i < numbers.size(); i++) {
17            // Iterate over all previous numbers
18            for (int j = 0; j < i; j++) {
19                // If the current number starts with any of the previous numbers, return false
20                if (numbers[i].find(numbers[j]) == 0) {
21                    return false;
22                }
23            }
24        }
25
26        // Return true if no number is a prefix of another
27        return true;
28    }
29};
30
1// Function to determine if any phone number is a prefix of another in the list
2function phonePrefix(numbers: string[]): boolean {
3    // Sort the array of numbers by their lengths in ascending order
4    numbers.sort((a, b) => a.length - b.length);
5
6    // Iterate over each number in the array
7    for (let i = 0; i < numbers.length; i++) {
8        // Compare current number with all previous numbers
9        for (let j = 0; j < i; j++) {
10            // Check if the current number starts with any of the previous numbers
11            if (numbers[i].startsWith(numbers[j])) {
12                // If a prefix is found, return false
13                return false;
14            }
15        }
16    }
17    // If no prefixes are found, return true
18    return true;
19}
20

Time and Space Complexity

The code sorts the list numbers based on their lengths. The time complexity for sorting is O(n \times \log n), where n is the number of strings in numbers.

After sorting, the code iterates over each string s in numbers and checks whether any prefix of s exists among the previous shorter strings. For each string s, it checks prefixes using s.startswith(t) for those strings t. The startswith operation takes O(m) time at most, where m is the length of the string being compared.

Thus, for each string in numbers, the worst-case number of prefix checks can be O(n), leading to O(n \times m) per string, resulting in a total time complexity for the loop of O(n^2 \times m).

Combining the sorting and the loop, the complete time complexity is O(n^2 \times m + n \times \log n).

The space complexity primarily considers the sorting operation and storing intermediate results. Sorting takes O(\log n) space due to the recursive nature of some sorting algorithms.

Storing strings and other operations take additional space, approximately O(m), where m is the average string length. Thus, the space complexity is O(m + \log n).

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:

What is the best way of checking if an element exists in a sorted array once in terms of time complexity? Select the best that applies.


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More