Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 586
bZhang Avatar asked Jul 28 '16 08:07

bZhang


People also ask

How do you find the number of digits in a number?

The formula will be integer of (log10(number) + 1). For an example, if the number is 1245, then it is above 1000, and below 10000, so the log value will be in range 3 < log10(1245) < 4. Now taking the integer, it will be 3. Then add 1 with it to get number of digits.

Which datatype will you use to store a number data of length 20 digits How will you declare this variable?

BigInteger n = new BigInteger("48565664968483514466");

How do you return the last digit of a number?

To find last digit of a number, we use modulo operator %. When modulo divided by 10 returns its last digit. To find first digit of a number is little expensive than last digit. To find first digit of a number we divide the given number by 10 until number is greater than 10.


1 Answers

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;
}
like image 184
Stefan Haustein Avatar answered Oct 06 '22 23:10

Stefan Haustein