How to improve: Given two integers, return the number of digits that they share

bZhang :

I received this question during an interview, the question is

Given two integers, return the number of digits that they share.

For example 129 and 431 would return 1 - as they both share the digit 1, but no other digit. 95 and 780 would return 0, since none of the integers overlap.

My thoughts are just iterate through the digits, store them into a hashtable and check .containsKey.

My Java solution:

public int commonDigits(int x, int y) {
     int count = 0;
     HashTable<Integer, String> ht = new HashTable<Integer, String>();

     while (x != 0) { 
         ht.put(x % 10, "x");
         x /= 10;
     }

     while (y != 0) {
         if ((ht.containsKey(y % 10)) {
             count++;
         }
         y /= 10;
     }

    return count;
}

But this takes up O(n) space and O(n + m) time, anyways I can improve this?

Stefan Haustein :

Why not just use some simple bit fiddling? 

public int commonDigits(int x, int y) {
  int dX = 0;
  while (x != 0) {
    dX |= 1 << (x % 10);
    x /= 10;
  }
  int count = 0;
  while (y != 0) {
    int mask = 1 << (y % 10);
    if ((dX & mask) != 0) {
      count ++;
      dX &= ~mask;
    }
    y /= 10;
  }
  return count;
}

This just sets a corresponding bit in dX for each digit in x. In the second loop, for each digit in x, the code checks whether it has an entry in dX. If so, it's counted and the bit is reset to avoid double-counting (note that this is missing in your code, consider 123 and 141). Obviously doesn't use any additional storage (dX and count could just be bytes if that matters).

Note that you don't need a HashTable in your solution -- you could just use a HasSet or a BitSet..

Your code translated to using a BitSet with the double-counting problem fixed:

public int commonDigits(int x, int y) {
  int count = 0;
  BitSet ht = new BitSet();

  while (x != 0) { 
     ht.set(x % 10, true);
     x /= 10;
  }
  while (y != 0) {
     if ((ht.get(y % 10)) {
         count++;
         ht.set(y % 10, false);
     }
     y /= 10;
  }
  return count;
}

Both snippets work exactly the same way, the latter just has some more overhead for the BitSet (and embedded array) instance.

This article shows why a BitSet is better than a boolean array in the general case: http://chrononsystems.com/blog/hidden-evils-of-javas-byte-array-byte

Edit:

If counting the same digit multiple times is actually desired (was not clear from the examples in the question), use an int array to store the counts:

public int commonDigits(int x, int y) {
  int count = 0;
  int[] digits = new int[10];

  while (x != 0) { 
     digits[x % 10]++;
     x /= 10;
  }
  while (y != 0) {
     if (digits[x % 10] > 0) {
         count++;
         digits[x % 10]--;
     }
     y /= 10;
  }
  return count;
}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=452546&siteId=1