2

I'm working on one algorithm and I'd appreciate some maths help. I'm not truly sure if it is maths problem exactly or it's just some data structure to use and problem will be solved. On input you got number M and number N (divided by space); and after N there is N digits (0 - 9). The problem is to find a shortest number you can create from these digits that will be divisible by your M number. For example input:

7 2 1 3

outputs:

133

simply because 133 (and only digits that can be used are 1 and 3) is divisible by 7 and it's the shortest number divisible by 7. Actually, the number doesn't need to be lowest, just the shortest. If there is no number that can be made from such digits, print -1. Thanks in advance if there is some genius mathematician :P

EDIT: There is no space limitation but the time limit should be 10seconds for any input, no matter Big-O.

qwerty_
  • 137
  • 1
  • 1
  • 8
  • I think that the part of `If there is no number that can be made from such digits, print -1` part is going to be really tricky, except for the obvious cases (where `M` is even and all the digits are odd or something similar). – shapiro yaacov Dec 14 '15 at 19:55
  • I really don't know if there is some mathematical mechanism to figure this out or to use some data structure and effectively solve such problem – qwerty_ Dec 14 '15 at 20:03
  • I'm thinking this should maybe be moved to http://math.stackexchange.com/ – shapiro yaacov Dec 14 '15 at 20:12
  • @shapiroyaacov maybe it would be OK to assume that the number must be small enough to fit into an integer type? At least that puts an upper bound on the problem. – Mark Ransom Dec 14 '15 at 20:12
  • 1
    @shapiroyaacov No, this seems like an algorithmic problem. Just go through all possible combinations of the digits, with the smallest sequences first, and determine if the resulting number divides evenly. – Mark Ransom Dec 14 '15 at 20:13
  • @MarkRansom - I agree with your second comment, but the first one seems forced. What I mean is that your idea is definitely a good way to go, specially if `N` is small. But the other condition would basically be saying that the number of digits is the requested number is some `x`, which would seem like an important variable, and if it was part of the question you would get it with the other ones. – shapiro yaacov Dec 14 '15 at 20:15
  • Just to get you on the right way guys. for input 39047 1 3 is output: http://pastebin.com/gNFpawyA ..so it's nohow limited by the size of integer – qwerty_ Dec 14 '15 at 20:20
  • well, @MarkRansom, there is no limit. I think that algorithmically either check combinations or check the multiples like Sorin's answer (go through `M`, `2M`, `3M`, ...). Any other trick is more math than code. Have I mentioned http://math.stackexchange.com/? – shapiro yaacov Dec 14 '15 at 20:24
  • You can use a variation of [this approach](http://stackoverflow.com/questions/22394257/how-to-count-integers-between-large-a-and-b-with-a-certain-property/22394258#22394258) to get the answer in O(N*M) – Niklas B. Dec 14 '15 at 20:26
  • Does the time/space complexity of the algorithm matter? – Jeremy Salwen Dec 14 '15 at 20:30
  • @JeremySalwen well, it wouldn't be very great if the algorithm would run half an hour for some input... – qwerty_ Dec 14 '15 at 20:35
  • @qwerty_ how are we supposed to judge that? There are plenty of times when I need an answer to a question, and I don't mind waiting a half hour for the answer if it's quick to code and I'm unlikely to need it more than once. – Mark Ransom Dec 14 '15 at 20:45
  • 1
    P.S. The way the question is phrased now, it's definitely a math problem and not an algorithm one. Since the answer is unbounded in space, you need a mathematical way of knowing if a possible answer exists because you have an infinite number of possibilities to check. – Mark Ransom Dec 14 '15 at 20:47

3 Answers3

2

Personally, I'd go about this in reverse. Take your M number, and multiply it by 1. Can you find M*1's digits among yours? If no, then go to M*2. You can stop at some arbitrarily high number. If you're using ints you can just stop to INT_MAX or whatever.

Edit : You can actually stop at INT_MAX-M.

Sorin Lascu
  • 395
  • 1
  • 4
  • 15
2

You could do it by using modular arithmetic to search for solutions one digit at a time

We can think of this problem as finding a sequence of n digits di ∈S such that enter image description here

If we do all our arithmetic mod m, we can think about it as a search for a path to the value "0" over the space of integers modulo m. Each step in the search is computed by appending an additional digit to our number. Horner's Method tells us that

enter image description here

Which means that for each digit we append to the number, we are multiplying the old value by 10, and adding the value of the new digit. Multiplication by 10 and addition of the digit are both easy to do mod m, and so we as we build up the number one digit at a time, we can keep track of its value mod m. The steps along the construction of the number trace out a "path" through the nodes based on the values mod 10 it reaches.

We will just perform a graph search on these paths to find the shortest "path" to (0). So for each step of the graph search, we compute the shortest "path" of length i (i.e. the smallest number with i digits) which ends on a given "node" (i.e. a value mod m).

So for example, let's imagine our digit set is {1,3} and m=9. Then our set of nodes for the search is going to be {(0),(1),...,(8)}. For each node, we store the "best path so far" to reach it. This simply means that for node (k), we store the smallest number we have found so far which equals k mod m.

At the first step in the search, we want to find the smallest 1 digit number which is equal to each value from 0,1,...,8 mod 9. Because our only available digits are 1 and 3, (1) and (3) are the only reachable nodes on the first step, and all other nodes are unreachable.

On the second step, we are trying to find the smallest two digit number which is equal to each value from 0,1,...,8 mod 9. From Horner's method, we remember that every two digit number is just 10*p + d where p is a 1-digit number. So we can get all of the nodes reachable in two steps by taking 10*p + d where p is a number reachable in 1 step, and d ∈ S. For any node (k), the "shortest path" to (k), i.e. the smallest value 10*p+d for which

enter image description here

will just be the smallest value of p for which

enter image description here

i.e. the smallest value of p (ties broken by d) for which

enter image description here

But notice now that because p is a 1-digit number, from the previous step we stored the smallest value of p for which this holds true. So we don't need to check every possible value of p, we only need to check the values for p which were the smallest possible paths to some node on the previous step.

Which is quite a lot of justification for the algorithm, but at the end of the day, it simply means we notice that

shortest path to (1) is 1 so
   with d=1, (2) is reachable in length 11 (p=1, d=1 10p+d=11=2 mod 9)
   with d=3, (4) is reachable in length 13 (p=1, d=3 10p+d=13=4 mod 9)
shortest path to (3) is 3 so
   with d=1, (4) is reachable in length 31 (p=3, d=1 10p+d=31=4 mod 9)
   with d=3, (6) is reachable in length 33 (p=3, d=3 10p+d=33=6 mod 9)

So the shortest paths to each of the reachable nodes are

(1)->1
(3)->3
(2)->11
(4)->13
(6)->33

And all the other nodes are unreachable.

At each iteration, we can repeat this same trick, that a i-digit number is just 10*p+d where p is a (i-1)-digit number. So we only need to search over the values of p stored from the previous step, and we will be guaranteed to find the shortest path of length <=i, i.e. the smallest number equal to k mod m.

Thus each step will potentially increase the size of the reachable nodes, and if 0 is ever reachable, we have found the minimal solution to our equation. But what about if 0 is not reachable, how will we tell when to stop searching? The key is that every iteration of our algorithm is exactly the same, so if at some iteration the set of reachable nodes does not change, then we know that it will never change again no matter how long we wait. Because there are a finite number of nodes, we know that either we must eventually reach zero, or our set of nodes must reach a fixed limit, terminating our algorithm.

So to finish our example, we have

shortest path to (2) is 11 so
   with d=1, (3) is reachable in length 111 (p=11, d=1 10p+d=111=3 mod 9)
   with d=3, (5) is reachable in length 13 (p=11, d=3 10p+d=113=5 mod 9)
shortest path to (4) is 13 so
   with d=1, (5) is reachable in length 131 (p=13, d=1 10p+d=131=5 mod 9)
   with d=3, (7) is reachable in length 133 (p=13, d=3 10p+d=133=7 mod 9)
shortest path to (6) is 33 so
   with d=1, (7) is reachable in length 331 (p=11, d=1 10p+d=331=7 mod 9)
   with d=3, (0) is reachable in length 333 (p=11, d=3 10p+d=333=0 mod 9)

which means we found the shortest path to (0), which is 333.

Space complexity:

For every value 0 <= i < m, we need to store a single digit and a pointer to the previous node in the path, which will require O(m) storage overall.

Running Time:

Every node in the graph requires us to consider a transition for each digit d &in; S. Thus the running time will be O(m*r) where r is the size of the set of acceptable digits S.

Bound on the solution:

Finally, we can use the algorithm to put a bound on the size of the solution. Since the search terminates after at most m steps, and we know it will examine solutions of at most size 10i in i steps, we know the solution must be bounded by 10m.

Obviously this algorithm is adaptable to bases other than 10.

Jeremy Salwen
  • 8,061
  • 5
  • 50
  • 73
0

I would just recursively search for such a number. The thing is you need a nice way to stop. I my algorithm I just poorly check for overflow. You can chose something better like the depth you want to search.

public static long find(int n, int[] digits, long current) {
    if (current > 0 && current % n == 0) {
        return current;
    }
    if (current < 0) {
        return Long.MAX_VALUE;//overflow
    }
    List<Long> all = new ArrayList<>();
    for (int i : digits) {
        long nc = current * 10 + i;
        all.add(find(n, digits, nc));
    }
    long found = Long.MAX_VALUE;
    for (long i : all) {
        if (i > 0) {
            found = Math.min(found, i);
        }
    }
    return found;
}

public static void main(String... args) {
    System.out.println("aaa");
    int d[] = {1, 3};
    System.out.println(find(7, d, 0));
}

The size of the number is limited by long max value. You can use BigInteger insted of long and go as much as you want

Liviu Stirb
  • 5,876
  • 3
  • 35
  • 40
  • but here, you are still limited by the size of datatype aren't you? But you can have a number which can be larger than even some unsigned long long... – qwerty_ Dec 14 '15 at 20:27
  • yes; but you can chose something like BigInteger in java an go as much as you want – Liviu Stirb Dec 14 '15 at 20:29
  • @qwerty_: That entirely depends on the language and data structure you use, which is irrelevant to your question since you didn't tag any language and only asked for an algorithm. – Vincent Savard Dec 14 '15 at 20:31
  • @VincentSavard yea, I know what you mean, I just think, that the code above will be very very slow as it's doing recursively every option – qwerty_ Dec 14 '15 at 20:34
  • 2
    @qwerty_: Being slow is not part of your question because you asked for an algorithm, which means you do not care about the implementation in a given language. If you have time and space constaints, edit them into your question. In the current state of your question, wondering about the size of the datatype or the speed of the implementation are just irrelevant. – Vincent Savard Dec 14 '15 at 20:36