views:

569

answers:

10

Hi guys,

I found this on the internet. It looks good an interview question.

I guess I got the working correct but programatically I haven't tried it.

SmallestInt

You are given an integer n. Return the smallest integer greater than or equal to n that
contains exactly k distinct digits in decimal notation.

Definition
Method signature: long GetSmallestInt(long n, int k)
Constraints
n will be between 1 and 10^18, inclusive.
k will be between 1 and 10, inclusive

Examples

  1. n=47, k=1
    Returns: 55
    Here, k is 1, so we're looking for a number whose digits are all equal. The smallest such number that is greater than or equal to 47 is 55.

  2. n=7, k=3
    Returns: 102
    We need three distinct digits here.

  3. n=69, k=2
    Returns: 69
    69 already consists of two different digits.

  4. n=12364, k=3
    Returns: 12411

So any answers??
code or algorithm
No language barriers .

Edit 8/2/2010 : Marked as "Community Wiki"

A: 

Does any answer work? There's always brute force.

Dan Tao
+1  A: 

One very simple solution would be to start with n and count up until the condition is fulfilled. (But i believe it should be possible to have a more "intelligent" solution)

nuriaion
A: 

It can be done O(n) where n is ... k in the question notation.

Will
A: 

A reasonable solution is to start with max(n,{k-digits long prefix of 1023456789}), and test values until one works.

Ofir
+2  A: 
#!/usr/bin/env ruby
Inf = 1/0.0 # isn't it about time to add this to the core library?

class Integer
  def smallest_integer(k)
    [self, '1023456789'[0,k].to_i].max.upto(Inf) {|i|
      break i if i.to_s.chars.to_a.uniq.length == k
    }
  end
end

So, how does this work?

Let's first remove the optimization:

class Integer
  def smallest_integer(k)
    upto(Inf) {|i|
      break i if i.to_s.chars.to_a.uniq.length == k
    }
  end
end

Integer#upto is an enumerator that does just what you expect: starting at self, it yields every integer between self and its argument. So, 42.upto(47) will yield 42, 43, 44, 45, 46 and 47. In this case, we are asking it to yield every integer between our starting point and infinity. Which will obviously not work, which is why we use the break keyword to break out of the loop.

And we pass an argument like this: break i to get a meaningful return value for the block, which is then also going to be the return value for the upto method which in turn is the return value for our method.

And when do we break? We break if the current integer (i), when we convert it to a string (to_s) and split it into characters (chars) has the number of unique digits (uniq.length) that we are looking for (k).

The to_a in there is only needed, because chars does not actually return an array of characters, but an iterator for each character and uniq doesn't work with iterators (because uniq needs to look at every element and iterators can be infinite), so we need to convert to an array first.

Actually, after I went to sleep last night, I realized that I had commited the mortal sin of Ruby in that code snippet: not knowing the true power of Enumerable. I had forgotten about the find method, I didn't know that find also works with Enumerators and I didn't know that upto returns an Enumerator when you don't pass a block. So, this is much more readable, I think:

class Integer
  def smallest_integer(k)
    upto(Inf).find {|i| i.to_s.chars.to_a.uniq.count == k }
  end
end

In this case, upto returns a lazy Enumerator, and find finds the first element for which the condition is true. (The condition is the same as before, except that yesterday I also forgot about count, which is just an alias for length, but makes the code flow a little better, when read out loud.)

Now, you can almost read that like an English sentence without even knowing Ruby, and will (sort of) make sense (which is how a well-written program should be):

When counting up to infinity, find a number for which the number of unique digits is k.

Okay, now let's add @Ofir's optimization back in: we take the string '1023456789', and starting from the beginning, we slice off k characters ([0,k]). Then we convert that to an integer (to_i) and look for the maximum of that and our original starting point (self):

[self, '1023456789'[0,k].to_i].max

Now we just stick that into our method:

class Integer
  def smallest_integer(k)
    [self, '1023456789'[0,k].to_i].max.upto(Inf).find {|i|
      i.to_s.chars.to_a.uniq.count == k
    }
  end
end

And of course, no Rubyist would ever leave the house without his testing framework in his pocket:

require 'test/unit'
class TestSmallestInteger < Test::Unit::TestCase
  def test_that_the_answer_for_n47_and_k1_is_55
    assert_equal 55, 47.smallest_integer(1)
  end
  def test_that_the_answer_for_n7_and_k3_is_102
    assert_equal 102, 7.smallest_integer(3)
  end
  def test_that_the_answer_for_n69_and_k2_is_69
    assert_equal 69, 69.smallest_integer(2)
  end
  def test_that_the_answer_for_n12364_and_k3_is_12411
    assert_equal 12411, 12364.smallest_integer(3)
  end
end
Jörg W Mittag
+1 Though I don't like the ruby syntax, you managed to make it quite easy to read and at the same time managed to get a solution that (at least) got the begining right!
Matthieu M.
hi Jörg,can you pls explain the answer?i'm not so familiar with ruby.looks very interesting.
Amitd
While this *looks* quite elegant, it is clearly brute force and Ο(n), when it *should* be Ο(k).
Jörg W Mittag
A: 

Short Answer in Haskell:

module Main where

import Data.List

getSmallestInt :: Integer -> Int -> Integer
getSmallestInt n k =
    head $ [x | 
        x <- [n..],
        (length . nub . show) x == k]
Kyle Butt
+3  A: 
Jason Orendorff
Should it be `1023456789` instead of `10023456789`?
KennyTM
No, 10023456789 is correct, because the desired answer is a number with exactly 4 distinct digits, not a number whose digits are *all* distinct. 10023 is the first five-digit number with 4 distinct digits.
Jason Orendorff
A: 

Python - 54 Chars

def S(n,k):
 while len(set(str(n)))!=k:n+=1
 return n

but we can also write it as a recursive lambda function which gets down to

Python - 51 chars

S=lambda n,k:n if len(set(str(n)))==k else S(n+1,k)

switching the condition saves another character

Python - 50 Chars

S=lambda n,k:S(n+1,k)if len(set(str(n)))!=k else n

using the and/or trick saves yet another character

Python - 49 Chars

S=lambda n,k:len(set(str(n)))!=k and S(n+1,k)or n

another switch of the condition and replace != with -

Python - 47 Chars

S=lambda n,k:k-len(set(str(n)))and S(n+1,k)or n
gnibbler
A: 

Golfscript - 18 Chars

~{\`.|,^}+{)}/-1=)

This works ok except for the 69,2 case. ie. where n is already the solution

$ echo 47 1| ../golfscript.rb smallest-integer.gs 
55
$ echo 7 3| ../golfscript.rb smallest-integer.gs 
102
$ echo 69 2| ../golfscript.rb smallest-integer.gs 
(eval):1:in `block in initialize': undefined method `rightparen' for nil:NilClass (NoMethodError)
    from ../golfscript.rb:285:in `call'
    from ../golfscript.rb:285:in `go'
    from (eval):8:in `block in initialize'
    from ../golfscript.rb:285:in `call'
    from ../golfscript.rb:285:in `go'
    from ../golfscript.rb:477:in `<main>'
$ echo 12364 3| ../golfscript.rb smallest-integer.gs 
12411
gnibbler
A: 

JavaScript - 143 chars

I decided to golf it...

i=readFile(0).split(/ /)
k=+i[1];
n=i[0]
for(;;n++){
a=(""+n).split('');
o={}
c=0
for(i in a){if(!o[a[i]])c++
o[a[i]]=1}
if(c==k)break}print(n)

Usage:

cp input.in 0 ; rhino thisfile.js
gnarf