Ilija Matoski

    ← Articles

    Coding Problem - Phone List

    Given a list of phone numbers, determine if it is consistent in the sense that no number is the prefix of another. Let’s say the phone catalogue listed these numbers:

    Emergency 911
    Alice 97 625 999
    Bob 91 12 54 26

    In this case, it’s not possible to call Bob, because the central would direct your call to the emergency line as soon as you had dialled the first three digits of Bob’s phone number. So this list would not be consistent.

    Input

    The first line of input gives a single integer, 1≤t≤40, the number of test cases. Each test case starts with n, the number of phone numbers, on a separate line, 1≤n≤10000. Then follows n lines with one unique phone number on each line. A phone number is a sequence of at most ten digits.

    2
    3
    911
    97625999
    91125426
    5
    113
    12340
    123440
    12345
    98346

    Output

    For each test case, output “YES” if the list is consistent, or “NO” otherwise.

    NO
    YES

    Solution

    Lets see how we would go about solving this.

    Since the maximum length of a number is 10 digits, we would iterate over the list backwards, and check for doubles.

    To be able to detect if the list is consistent or not, the algorithm would be something along these lines.

    Algorithm 1
    1. Group the numbers by length in an array (Hash tree)
    2. Check for doubles, if there is a double then it’s not consistent, don’t proceed with the test, even though it says it’s unique, you never know what could happen, so it doesn’t hurt to try, and it doesn’t hurt the performance too much
    3. Iterate over the the array backwards from the biggest available number length
      1. Check for doubles, and if there are it’s not consistent, so break
      2. If MAX_NUMBER_LENGTH = CURRENT_NUMBER_LENGTH or CURRENT_NUMBER_LENGTH == MAX_NUMBER_LENGTH_IN_LIST, then we continue as it’s consistent and there are no duplicates
      3. Build the array from the previous data set and merge into current so we can keep the results
      4. Create an array the we gonna use to compare
      5. Check if the keys are present in the array
      6. Break if we detected a match
      7. Add the values to current index, so we can compare with previous one on the next run

    This is implemented in PHP

    Algorithm 2

    Another way to do this is to use a Tree, and each of the Nodes needs to have 10 leafs (one for each digit of a number), and you build the Tree by appending another Tree onto the leaf. If it’s a new leaf (the node is consistent if the digit position of the processing number equals the length of the number). If it’s not a new leaf, but the node is consistent, then the list of number is not consistent, also the same applies if the digit position of the processing number equals the length of the number.

    This is implemented in Java

    Implementations

    There are a lot of ways to do this, some faster some slower, a slower one would be to use a sort algorithm, but this is not good for really big values.

    The input sample provided by the problem is OK, but we need better one, so here is firstly a script that will generate random test cases, for us to test. Simplest is here in PHP, but we can use it for testing in the other languages too.

    <?php
    $test = rand(1, 40);
    $testname = utime();
    file_put_contents("rt-$testname", "$test\n");
    $line = 1;
    for ($i = 0; $i < $test; $i++) {
    $numbers = rand(1, 10000);
    file_put_contents("rt-$testname", "$numbers\n", FILE_APPEND);
    $line++;
    for ($n = 0; $n < $numbers; $n++) {
    $number = rand(100, 9999999999);
    file_put_contents("rt-$testname", "$number\n", FILE_APPEND);
    $line++;
    }
    }
    PHP
    <?php
    $output = array();
    $stdin = fopen('php://stdin', 'r');
    $totalTests = trim(fgets($stdin));
    $maxLengthNumber = 10;
    for ($i = 0; $i < $totalTests; $i++) {
    $totalNumbers = trim(fgets($stdin));
    $list = array();
    $numbers = array();
    // 1. Group the numbers by length in an array
    for ($a = 0; $a < $totalNumbers; $a++) {
    $phone = trim(fgets($stdin));
    $numbers[] = $phone;
    $digits = strlen($phone);
    $list[$digits][] = $phone;
    }
    if ($totalNumbers != count(array_flip($numbers))) {
    // 2. Check for doubles, if there is a double then it's not consistent
    $isConsistent = false;
    } else {
    $isConsistent = true;
    // 3. Iterate over the the array
    $keys = array_keys($list);
    sort($keys);
    $keys = array_reverse($keys, SORT_NUMERIC);
    $max_key = max($keys);
    foreach ($keys as $index => $key) {
    $totalItems = count($list[$key]);
    // 3.1. Check for doubles, and if there are it's not consistent, so break
    if ($totalItems != count(array_flip($list[$key]))) {
    $isConsistent = false;
    break;
    }
    // 3.2. If MAX_NUMBER_LENGTH = CURRENT_NUMBER_LENGTH || $key == $max_key, then we continue as it's consistent and there are no duplicates
    if ($maxLengthNumber == $key || $key == $max_key) {
    $isConsistent = true;
    continue;
    }
    // 3.3. Build the array from the previous data set and merge into current so we can keep the results
    $prevCut = array();
    $prev = array();
    $currentListIndex = $keys[$index];
    $prevListIndex = $keys[$index + 1];
    // 3.4. Create an array the we gonna use to compare
    foreach ($list[$prevListIndex] as $idx => &$val) {
    $prevCut[$idx] = substr($val, 0, $key);
    $prev[$idx] = $val; // point it as a reference for faster memory access
    }
    // 3.5. Check if the keys are present in the array
    $prevCutKeys = array_flip($prevCut);
    foreach ($list[$currentListIndex] as $idx => $val) {
    if (isset($prevCutKeys[$val])) {
    $isConsistent = false;
    break;
    } else {
    $isConsistent = true;
    }
    }
    // 3.6. Break if we detected a match
    if (!$isConsistent) {
    break;
    }
    // 3.7. Add the values to current index, so we can compare with previous one on the next run
    foreach ($prev as $val) {
    $list[$currentListIndex][] = $val;
    }
    }
    }
    array_push($output, $isConsistent ? "YES" : "NO");
    }
    $out = fopen('php://output', 'w'); //output handler
    fputs($out, join("\n", $output) . "\n"); //writing output operation
    fclose($out);
    Java
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    public class PhoneList {
    public static final String YES = "YES";
    public static final String NO = "NO";
    private static Tree tree = new Tree();
    private static boolean isConsistent = true;
    private static class Tree {
    int node = 0;
    boolean isCons = false;
    Tree[] next = new Tree[10];
    public void setNext(int index, Tree t) {
    next[index] = t;
    }
    public Tree getTree(int index) {
    return next[index];
    }
    }
    // Should be on a separate class
    public static void main(String[] args) {
    PhoneList phoneList = new PhoneList();
    try {
    phoneList.build();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    public void build() throws IOException {
    BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
    int t = Integer.parseInt(reader.readLine());
    for (int i = 0; i < t; ++i) {
    int n = Integer.parseInt(reader.readLine());
    tree = new Tree();
    isConsistent = true;
    for (int j = 0; j < n; ++j) {
    String phone = reader.readLine();
    if (isConsistent)
    buildTree(phone);
    }
    if (isConsistent)
    System.out.println(YES);
    else
    System.out.println(NO);
    }
    }
    private void buildTree(String s) {
    int len = s.length();
    Tree auxTree = tree;
    for (int i = 0; i < len; ++i) {
    int ch = Integer.parseInt(s.substring(i, i + 1));
    Tree aux = auxTree.next[ch];
    if (aux == null) {
    aux = new Tree();
    aux.node = 1;
    if (i == len - 1)
    aux.isCons = true;
    auxTree.setNext(ch, aux);
    auxTree = aux;
    } else {
    if (aux.isCons) {
    isConsistent = false;
    break;
    }
    if (i == len - 1) {
    isConsistent = false;
    break;
    }
    auxTree = aux;
    }
    }
    }
    }