Looking for better algorithm to solve this kind of a probability/combinatorics game - algorithm

Lets say we have the 10 integers from 1 to 10.
We also have some players who are each given a different random number from this set.
Now players start to say information about his or her number by saying: my number is in a subset of initial 1 to 10 set. For example my number is 8,9 or 10.
We want to make assumptions about number of players who didn't say anything yet (of-course its same assumption about each silent player given initial information)
Lets say we have 5 players and the first 3 players said one by one:
mine is 8, 9 or 10
mine is 7 or 6
mine is 7, 6, 9 or 10
Now we need to calculate what are the odds (probability) that next player has a specific number, like what are the odds that next player has a number in 7.
Its just an example of course and information can be given in any form by each player (like 1 or 10, 1 through 10 etc)
Is this some kind of well known problem or maybe someone sees a good approach?
I really want this to be performant, so bruteforcing isn't good. I am thinking it could be directly connected to Bayes theorem but not 100% sure it can be applied here.
EXAMPLE:
Simple case 2 players and 12345 numbers. First player has 4 or 5.
Then for second player he has 25% to have 1, but only 12.5% to have 4 because there are 2 possible outcomes after first players says information about his hand.
1234 or 1235, we can see that 1 is (1/4 * 2) /2 =1/4 and 4 is (1/4 * 1) / 2= 1/8
This is what I call a brute force solution, compute all possible combinations and derive number probability by analyzing each of them.
UPDATE
Solution suggested by Mr.Wizard works.
Here is the code if your curious how it looks:
class Program
{
static void Main()
{
int length = 5;
double[][] matrix = new double[length][];
for (int i = 0; i < length; i++) {
matrix[i] = new double[length];
}
for (int i = 0; i < length; i++) {
for (int j = 0; j < length; j++) {
matrix[i][j] = 1;
}
}
matrix[0] = new double[] { 0, 0, 0, 1, 1 };
matrix[1] = new double[] { 0, 0, 1, 1, 0 };
matrix[2] = new double[] { 0, 0, 0, 0, 1 };
DumpMatrix(matrix);
while(true)
{
NormalizeColumns(matrix);
DumpMatrix(matrix);
NormalizeRows(matrix);
DumpMatrix(matrix);
Console.ReadLine();
}
}
private static void NormalizeRows(double[][] matrix)
{
for (int i = 0; i < matrix.Length; i++)
{
double sum = matrix[i].Sum();
for (int j = 0; j < matrix.Length; j++) {
matrix[i][j] = matrix[i][j] / sum;
}
}
}
private static void NormalizeColumns(double[][] matrix)
{
for (int j = 0; j < matrix.Length; j++)
{
double columnSum = 0;
for (int i = 0; i < matrix.Length; i++)
{
columnSum += matrix[i][j];
}
for (int i = 0; i < matrix.Length; i++) {
matrix[i][j] = matrix[i][j] / columnSum;
}
}
}
private static void DumpMatrix(double[][] matrix)
{
for (int i = 0; i < matrix.Length; i++) {
for (int j = 0; j < matrix.Length; j++) {
Console.Write(matrix[i][j].ToString("0.#####").PadRight(8));
}
Console.WriteLine();
}
Console.WriteLine();
}
}
Although from this example its pretty clear that its approaching final results not very fast.
Here player 3 has exactly 5, players one and two can have 4 or 5 and 3 or 4 respectively, which means that player one has 4 cause player 3 got 5 and player 2 has 3 cause player 2 got 4. But we approach 1 value for players 1 and 2 in matching column after many many iterations.

Try constructing a graph with players on one side and numbers on the other. There is an edge between a player and a number if and only if the player could have that number based on what they've said. You want, for each edge, the probability that a uniform random perfect matching contains that edge.
Unfortunately, if this problem has an exact polynomial-time algorithm, then #P, a class which contains NP (and in fact the entire polynomial hierarchy, by Toda's theorem), is equal to P.
It is possible, in theory at least, to estimate the probability, via a complicated algorithm due to Jerrum, Sinclair, and Vigoda. I'm not sure anyone has ever implemented that algorithm.

You should build a probability tree diagram.
For your example:
__
|___ 0.5 A=4 __
| |___ 0.25 B=1
| |___ 0.25 B=2
| |___ 0.25 B=3
| |___ 0.25 B=5
|___ 0.5 A=5 __
|___ 0.25 B=1
|___ 0.25 B=2
|___ 0.25 B=3
|___ 0.25 B=4
The tree represents statements such as p(B=1|A=4)=0.25
So
p(B=1|A=4 or A=5)= p(B=1|A=4)+p(B=1|A=5)= 0.5*0.25 + 0.5*0.25= 0.25
and
p(B=4|A=4 or A=5)= p(B=4|A=4)+p(B=4|A=5)= 0 + 0.5*0.25= 0.125
You can dynamically expend the tree at any stage of the game and calculate the probability for each assumption accordingly.
I believe that for the general case there are no shortcuts.

I may be well off the mark here, but I think that a process of repetitive normalization of each row and column will converge on the correct values.
If you start with a n*n matrix with zeros representing what cannot be, and ones representing what can, for your example:
0 0 0 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
Meaning, that row #1, representing player #1, can be only either 4 or 5, and nothing else is known. Then, if we normalize each row such that it sums to 1, we get:
0. 0. 0. 0.5 0.5
0.2 0.2 0.2 0.2 0.2
0.2 0.2 0.2 0.2 0.2
0.2 0.2 0.2 0.2 0.2
0.2 0.2 0.2 0.2 0.2
And then, for each column:
0. 0. 0. 0.384615 0.384615
0.25 0.25 0.25 0.153846 0.153846
0.25 0.25 0.25 0.153846 0.153846
0.25 0.25 0.25 0.153846 0.153846
0.25 0.25 0.25 0.153846 0.153846
Repeat this process 15 times, and we get:
0. 0. 0. 0.5 0.5
0.25 0.25 0.25 0.125 0.125
0.25 0.25 0.25 0.125 0.125
0.25 0.25 0.25 0.125 0.125
0.25 0.25 0.25 0.125 0.125
If the original parameters are not impossible, then each row and column in the final matrix should sum to ~= 1.
I offer no proof that this is correct, but if you already have a working brute force implementation it should be easy to check for correlation of results.

Not sure about the exact calculation right now, but i think you can do it easier than with a complete tree.
In the easy example:
There are 5 Numbers and you want to know the probability for B to have a 3:
There are always 4 possible numbers because one is already taken
In no case the 3 can be taken, so whatever A does, the 3 is always one of the 4 numbers.
From that statements we can directly say that the probability is 1/4 = 25%
For a 1 and 2 it is the same, and for 4 and 5 you have only a 50% chance of the number beeing in the pool, so it reduces to 0.25*0.5 = 0.125
For the bigger Example:
1 to 10, 5 players as you stated above.
Now say you want to know the possibility of a 6.
Both Players that did not say anything have the same probabilities.
One said he has a 6 with 25% and One said he has a 6 with 50%
Im not sure right now how exactly that is done, but you can now calculate the probability of "one of them has a 6". As one has 50% and the other 25% add to it, it should be like 60% or something. (not just add them... two times 50% is a good chance, but no sure hit).
Lets just assume it is 60% for this example. Now we have 10 Numbers, of which 3 are taken which leaves us 7 to choose from = 1/7 ~ 14%.
So for any number which is available we have 14%. But now the 6 is in the pool only 40% of the time, so I think we have 0.14 * 0.4 = 0.056 which means 5.6% that we have a 6.
Whatever information you have, you can calculate the probability of the number you want to know about to be taken, and the probability of hitting exactly the one of X left and multiply them.

Related

Fitness Proportionate Selection when some fitnesses are 0

I have a question about what to do with the fitnesses (fitness'?) that are 0 when getting the fitness proportionate probabilities. Should the container for the members be sorted by highest fitness first, then do code similar to this:
for all members of population
sum += fitness of this individual
end for
for all members of population
probability = sum of probabilities + (fitness / sum)
sum of probabilities += probability
end for
loop until new population is full
do this twice
number = Random between 0 and 1
for all members of population
if number > probability but less than next probability then you have been selected
end for
end
create offspring
end loop
My problem that I am seeing as I go through one iteration by hand with randomly generated members is that I have some member's fitness as 0, but when getting the probability of those members, it keeps the same probability as the last non zero member. Is there a way I can separate the non zero probabilities from the zero probabilities? I was thinking that even if I sort based on highest fitness, the last non zero member would have the same probability as the zero probabilities.
Consider this example:
individual fitness(i) probability(i) partial_sum(i)
1 10 10/20 = 0.50 0.50
2 3 3/20 = 0.15 0.5+0.15 = 0.65
3 2 2/20 = 0.10 0.5+0.15+0.1 = 0.75
4 0 0/20 = 0.00 0.5+0.15+0.1+0.0 = 0.75
5 5 5/20 = 0.25 0.5+0.15+0.1+0.0+0.25 = 1.00
------
Sum 20
Now if number = Random between [0;1[ we are going to pick individual i if:
individual condition
1 0.00 <= number < partial_sum(1) = 0.50
2 0.50 = partial_sum(1) <= number < partial_sum(2) = 0.65
3 0.65 = partial_sum(2) <= number < partial_sum(3) = 0.75
4 0.75 = partial_sum(3) <= number < partial_sum(4) = 0.75
5 0.75 = partial_sum(4) <= number < partial_sum(5) = 1.00
If an individual has fitness 0 (e.g. I4) it cannot be selected because of its selection condition (e.g. I4 has the associated condition 0.75 <= number < 0.75).

Running time/time complexity for while loop with square root

This question looks relatively simple, but I can't seem to find the running time in terms of n.
Here is the problem:
j = n;
while(j >= 2) {
j = j^(1/2)
}
I don't really need the total running time, I just need to know how to calculate the amount of times the second and third lines are hit (they should be the same). I'd like to know if there is some sort of formula for finding this, as well. I can see that the above is the equivalent of:
for(j = n; n >= 2; j = j^(1/2)
Please note that the type of operation doesn't matter, each time a line is executed, it counts as 1 time unit. So line 1 would just be 1 time unit, line 2 would be:
0 time units if n were 1,
1 time unit if n were 2,
2 time units if n were 4,
3 time units if n were 16, etc.
Thanks in advance to anyone who offers help! It is very much appreciated!
Work backwards to get the number of time units for line 2:
time
n n log_2(n) units
1 1 0 0
2 2 1 1
4 4 2 2
16 16 4 3
16^2 256 8 4
(16^2)^2 65536 16 5
((16^2)^2)^2) ... 32 6
In other words, for the number of time units t, n is 2^(2^(t-1)) except for the case t = 0 in which case n = 1.
To reverse this, you have
t = 0 when n < 2
t = log2(log2(n)) + 1 when n >= 2
where log2(x) is known as the binary logarithm of x.

Optimal Square Covering in 2D Matrix (Minimize Coverage Cost)

I came across the following programming challenge recently:
Statement
Consider a 2D square matrix of size NxN containing 0s and 1s. You have to cover all the 1s in the matrix using squares of size 1, 2 or 3. The coverage cost using square of size 1 is 2, using square of size 2 is 4 and using square of size 3 is 7. The objective is to find the minimum coverage cost to cover all the 1s in matrix.
Constraints
1 <= N <= 100
General Comments
Overlapping covering squares are allowed.
It is not necessary that the covering square should cover only 1s -
they may cover cells containing 0s as well.
Example
Consider the following matrix as an example:
0 0 0 0 0 0 0 0
0 1 1 0 0 0 0 0
0 1 1 1 0 0 0 0
0 0 1 1 1 0 0 0
0 0 0 1 0 0 0 0
0 0 0 0 0 1 0 0
0 0 0 0 0 1 1 0
0 0 0 0 0 0 1 0
In above example, minimum coverage cost is 7x1 + 4x2 + 2x1 = 17. Another covering is possible with minimum coverage cost of 7x1 + 4x1 + 2x3 = 17.
My Approach
I tried to approach the problem in the following manner:
Use square of size 3 to cover 1s where number of 1s in any 3x3 area is >= 5. Remove those 1s from the matrix.
Next, use square of size 2 to cover 1s where number of 1s in any 2x2
area is >= 2. Remove those 1s from the matrix.
Cover remaining 1s with sqaure of size 1.
This approach is greedy and is not optimal. For the example above, my approach gives answer 7x1 + 4x2 + 2x2 = 19 which is not optimal.
Any pointers about how to approach this problem or references to known problems which can be used to solve this one are appreciated. Thanks.
Update
Taking a cue from #bvdb answer, I updated the approach to select the coverage squares based on the number of 1s they are covering. However, the approach is still non-optimal. Consider a scenario where we have the following arrangement:
1 0 1
0 0 0
1 0 1
This arrangement will be covered using 4 coverage squares of size 1 whereas they must be covered using 1 square of size 3. In general, 5 1s in 3x3 area must be covered using different strategies based on how they are spread in the area. I can hardcode it for all types of cases, but I am looking for an elegant solution, if it exists.
Your problem is a typical Packing problem.
Your approach of fitting the biggest box first makes perfect sense.
A simple way to make your algorithm better, is to just give preference to 3x3 squares with maximum conent.
Example:
Use square of size 3 to cover 1s where number of 1s in any 3x3 area is = 9. Remove those 1s from the matrix.
Idem, but where area is = 8.
Idem, but where area is = 7.
Idem, but where area is = 6.
Next, use square of size 2 to cover 1s where number of 1s in any 2x2 area is = 4. Remove those 1s from the matrix.
etc ...
Monte carlo method
But if you want to add overlap, then it gets more tricky. I am sure you could work it out mathematically. However, when logic becomes tricky, then the Monte Carlo method always comes to mind:
Monte Carlo methods (or Monte Carlo experiments) are a broad class of computational algorithms that rely on repeated random sampling to obtain numerical results. They are often used in physical and mathematical problems and are most useful when it is difficult or impossible to use other mathematical methods.
Monte Carlo trades coded logic for speed and randomness:
STEP 1: repeat 4 times:
cor = randomCoordinate()
if ( hasContent(cor, 3) ) then putSquare(cor, 3)
STEP 2: repeat 16 times:
cor = randomCoordinate()
if ( hasContent(cor, 2) ) then putSquare(cor, 2)
STEP 3: corList = getFreeSquaresWithContent()
putSquare(corlist, 1)
calculateScore()
store used squares and score.
This code should be simple but really fast.
Then run this 100.000 times, and keep the top 10 scores.
Which 3x3 squares did the winners use most often?
Use this information as a "starting position".
Now, run it again from STEP2 using this starting position.
This means that the 100.000 iterations don't have to focus on the 3x3 squares any more, they immediately start adding 2x2 squares.
PS: The number of iterations you do (e.g. 100.000) is really a matter of the required response time and the required accuracy. You should test this to find out what is acceptable.
If you are looking for a deterministic approach.
I think the best thing to do is to sort all possible patterns in an optimal order. There are only 394 relevant patterns. There is no need to hardcode them, you can generate them on-the-fly.
First our definitions (rules of the game). Each square has a size and a cost.
class Square
{
private int size;
private int cost;
Square(int pSize, int pCost)
{
size = pSize;
cost = pCost;
}
}
And there are only 3 types of squares. squareOne keeps the cost of a 1x1 matrix, squareTwofor a 2x2 and squareThree for a 3x3 matrix.
Square squareOne = new Square(1, 2);
Square squareTwo = new Square(2, 4);
Square squareThree = new Square(3, 7);
List<Square> definitions = Arrays.asList(squareOne, squareTwo, squareThree);
We are going to have to store each pattern with its cost, number of hits, and its cost per hit (efficiency). So here follows the class that I am using to store it. Note that this class contains methods that help to perform the sorting as well as conversions to a matrix of boolean's (1/0 values).
class ValuedPattern implements Comparable<ValuedPattern>
{
private long pattern;
private int size;
private int cost;
private double costPerHit;
private int hits;
ValuedPattern(long pPattern, int pSize, int pCost)
{
pattern = pPattern;
cost = pCost;
size = pSize;
// calculate the efficiency
int highCount = 0;
BitSet set = BitSet.valueOf(new long[]{pattern});
for (int i = 0; i < set.size(); i++)
{
if (set.get(i)) highCount++;
}
hits = highCount;
costPerHit = (double) cost / (double) hits;
}
public boolean[][] toArray()
{
boolean[][] patternMatrix = new boolean[size][size];
BitSet set = BitSet.valueOf(new long[]{pattern});
for (int i = 0; i < size; i++)
{
for (int j = 0; j < size; j++)
{
patternMatrix[i][j] = set.get(i * size + j);
}
}
return patternMatrix;
}
/**
* Sort by efficiency
* Next prefer big matrixes instead of small ones.
*/
#Override
public int compareTo(ValuedPattern p)
{
if (p == null) return 1;
if (costPerHit < p.costPerHit) return -1;
if (costPerHit > p.costPerHit) return 1;
if (hits > p.hits) return -1;
if (hits < p.hits) return 1;
if (size > p.size) return -1;
if (size < p.size) return 1;
return Long.compare(pattern, p.pattern);
}
#Override
public boolean equals(Object obj)
{
if (! (obj instanceof ValuedPattern)) return false;
return (((ValuedPattern) obj).pattern == pattern) &&
(((ValuedPattern) obj).size == size);
}
}
Next we are going to store all possible patterns in a sorted collection (i.e. a TreeSet sorts its content automatically using the compareTo method of the object).
Since your patterns are just 0 and 1 values, you can think of them as numeric values (long is a 64bit integer which is more than enough) which can be converted later to a boolean matrix. The size of the pattern is the same as the number of bits of that numeric value. Or in other words there are 2^x possible values, with x being the number of cells in your pattern.
// create a giant list of all possible patterns :)
Collection<ValuedPattern> valuedPatternSet = new TreeSet<ValuedPattern>();
for (Square square : definitions)
{
int size = square.size;
int bits = size * size;
long maxValue = (long) Math.pow(2, bits);
for (long i = 1; i < maxValue; i++)
{
ValuedPattern valuedPattern = new ValuedPattern(i, size, square.cost);
// filter patterns with a rediculous high cost per hit.
if (valuedPattern.costPerHit > squareOne.cost) continue;
// and store the result for later
valuedPatternSet.add(valuedPattern);
}
}
After composing the list, the patterns are already sorted according to efficiency. So now you can just apply the logic that you already have.
// use the list in that order
for (ValuedPattern valuedPattern : valuedPatternSet)
{
boolean[][] matrix = valuedPattern.toArray();
System.out.println("pattern" + Arrays.deepToString(matrix) + " has cost/hit: " + valuedPattern.costPerHit);
// todo : do your thing :)
}
The demo code above outputs all patterns with their efficiency. Note that smaller patterns sometimes have a better efficiency than the bigger ones.
Pattern [[true, true, true], [true, true, true], [true, true, true]] has cost/hit: 0.7777777777777778
Pattern [[true, true, true], [true, true, true], [true, true, false]] has cost/hit: 0.875
Pattern [[true, true, true], [true, true, true], [true, false, true]] has cost/hit: 0.875
Pattern [[true, true, true], [true, true, true], [false, true, true]] has cost/hit: 0.875
...
The entire thing runs in just a couple of ms.
EDIT:
I added some more code, which I am not going to drop here (but don't hesitate to ask, then I'll e-mail it to you). But I just wanted to show the result it came up with:
EDIT2:
I am sorry to tell you that you are correct to question my solution. It turns out there is a case where my solution fails:
0 0 0 0 0 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 1 1 1 1 0
0 0 0 0 0 0
My solution is greedy, in the sense that it immediatly tries to apply the most efficient pattern:
1 1 1
1 1 1
1 1 1
Next only the following remains:
0 0 0 0 0 0
0 _ _ _ 1 0
0 _ _ _ 1 0
0 _ _ _ 1 0
0 1 1 1 1 0
0 0 0 0 0 0
Next it will use three 2x2 squares to cover the remains.
So the total cost = 7 + 3*4 = 19
The best way of course would have been to use four 2x2 squares.
With a total cost of 4*4 = 16
Conclusion: So, even though the first 3x3 was very efficient, the next 2x2 patterns are less efficient. Now that you know this exception you could add it to the list of patterns. E.g. a square with size 4 has cost 16. However, that wouldn't solve it, a 3x3 would still have a lower cost/hit and would always be considered first. So, my solution is broken.

nᵗʰ ugly number

Numbers whose only prime factors are 2, 3, or 5 are called ugly numbers.
Example:
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, ...
1 can be considered as 2^0.
I am working on finding nth ugly number. Note that these numbers are extremely sparsely distributed as n gets large.
I wrote a trivial program that computes if a given number is ugly or not. For n > 500 - it became super slow. I tried using memoization - observation: ugly_number * 2, ugly_number * 3, ugly_number * 5 are all ugly. Even with that it is slow. I tried using some properties of log - since that will reduce this problem from multiplication to addition - but, not much luck yet. Thought of sharing this with you all. Any interesting ideas?
Using a concept similar to Sieve of Eratosthenes (thanks Anon)
for (int i(2), uglyCount(0); ; i++) {
if (i % 2 == 0)
continue;
if (i % 3 == 0)
continue;
if (i % 5 == 0)
continue;
uglyCount++;
if (uglyCount == n - 1)
break;
}
i is the nth ugly number.
Even this is pretty slow. I am trying to find the 1500th ugly number.
A simple fast solution in Java. Uses approach described by Anon..
Here TreeSet is just a container capable of returning smallest element in it. (No duplicates stored.)
int n = 20;
SortedSet<Long> next = new TreeSet<Long>();
next.add((long) 1);
long cur = 0;
for (int i = 0; i < n; ++i) {
cur = next.first();
System.out.println("number " + (i + 1) + ": " + cur);
next.add(cur * 2);
next.add(cur * 3);
next.add(cur * 5);
next.remove(cur);
}
Since 1000th ugly number is 51200000, storing them in bool[] isn't really an option.
edit
As a recreation from work (debugging stupid Hibernate), here's completely linear solution. Thanks to marcog for idea!
int n = 1000;
int last2 = 0;
int last3 = 0;
int last5 = 0;
long[] result = new long[n];
result[0] = 1;
for (int i = 1; i < n; ++i) {
long prev = result[i - 1];
while (result[last2] * 2 <= prev) {
++last2;
}
while (result[last3] * 3 <= prev) {
++last3;
}
while (result[last5] * 5 <= prev) {
++last5;
}
long candidate1 = result[last2] * 2;
long candidate2 = result[last3] * 3;
long candidate3 = result[last5] * 5;
result[i] = Math.min(candidate1, Math.min(candidate2, candidate3));
}
System.out.println(result[n - 1]);
The idea is that to calculate a[i], we can use a[j]*2 for some j < i. But we also need to make sure that 1) a[j]*2 > a[i - 1] and 2) j is smallest possible.
Then, a[i] = min(a[j]*2, a[k]*3, a[t]*5).
I am working on finding nth ugly number. Note that these numbers are extremely sparsely distributed as n gets large.
I wrote a trivial program that computes if a given number is ugly or not.
This looks like the wrong approach for the problem you're trying to solve - it's a bit of a shlemiel algorithm.
Are you familiar with the Sieve of Eratosthenes algorithm for finding primes? Something similar (exploiting the knowledge that every ugly number is 2, 3 or 5 times another ugly number) would probably work better for solving this.
With the comparison to the Sieve I don't mean "keep an array of bools and eliminate possibilities as you go up". I am more referring to the general method of generating solutions based on previous results. Where the Sieve gets a number and then removes all multiples of it from the candidate set, a good algorithm for this problem would start with an empty set and then add the correct multiples of each ugly number to that.
My answer refers to the correct answer given by Nikita Rybak.
So that one could see a transition from the idea of the first approach to that of the second.
from collections import deque
def hamming():
h=1;next2,next3,next5=deque([]),deque([]),deque([])
while True:
yield h
next2.append(2*h)
next3.append(3*h)
next5.append(5*h)
h=min(next2[0],next3[0],next5[0])
if h == next2[0]: next2.popleft()
if h == next3[0]: next3.popleft()
if h == next5[0]: next5.popleft()
What's changed from Nikita Rybak's 1st approach is that, instead of adding next candidates into single data structure, i.e. Tree set, one can add each of them separately into 3 FIFO lists. This way, each list will be kept sorted all the time, and the next least candidate must always be at the head of one ore more of these lists.
If we eliminate the use of the three lists above, we arrive at the second implementation in Nikita Rybak' answer. This is done by evaluating those candidates (to be contained in three lists) only when needed, so that there is no need to store them.
Simply put:
In the first approach, we put every new candidate into single data structure, and that's bad because too many things get mixed up unwisely. This poor strategy inevitably entails O(log(tree size)) time complexity every time we make a query to the structure. By putting them into separate queues, however, you will see that each query takes only O(1) and that's why the overall performance reduces to O(n)!!! This is because each of the three lists is already sorted, by itself.
I believe you can solve this problem in sub-linear time, probably O(n^{2/3}).
To give you the idea, if you simplify the problem to allow factors of just 2 and 3, you can achieve O(n^{1/2}) time starting by searching for the smallest power of two that is at least as large as the nth ugly number, and then generating a list of O(n^{1/2}) candidates. This code should give you an idea how to do it. It relies on the fact that the nth number containing only powers of 2 and 3 has a prime factorization whose sum of exponents is O(n^{1/2}).
def foo(n):
p2 = 1 # current power of 2
p3 = 1 # current power of 3
e3 = 0 # exponent of current power of 3
t = 1 # number less than or equal to the current power of 2
while t < n:
p2 *= 2
if p3 * 3 < p2:
p3 *= 3
e3 += 1
t += 1 + e3
candidates = [p2]
c = p2
for i in range(e3):
c /= 2
c *= 3
if c > p2: c /= 2
candidates.append(c)
return sorted(candidates)[n - (t - len(candidates))]
The same idea should work for three allowed factors, but the code gets more complex. The sum of the powers of the factorization drops to O(n^{1/3}), but you need to consider more candidates, O(n^{2/3}) to be more precise.
A lot of good answers here, but I was having trouble understanding those, specifically how any of these answers, including the accepted one, maintained the axiom 2 in Dijkstra's original paper:
Axiom 2. If x is in the sequence, so is 2 * x, 3 * x, and 5 * x.
After some whiteboarding, it became clear that the axiom 2 is not an invariant at each iteration of the algorithm, but actually the goal of the algorithm itself. At each iteration, we try to restore the condition in axiom 2. If last is the last value in the result sequence S, axiom 2 can simply be rephrased as:
For some x in S, the next value in S is the minimum of 2x,
3x, and 5x, that is greater than last. Let's call this axiom 2'.
Thus, if we can find x, we can compute the minimum of 2x, 3x, and 5x in constant time, and add it to S.
But how do we find x? One approach is, we don't; instead, whenever we add a new element e to S, we compute 2e, 3e, and 5e, and add them to a minimum priority queue. Since this operations guarantees e is in S, simply extracting the top element of the PQ satisfies axiom 2'.
This approach works, but the problem is that we generate a bunch of numbers we may not end up using. See this answer for an example; if the user wants the 5th element in S (5), the PQ at that moment holds 6 6 8 9 10 10 12 15 15 20 25. Can we not waste this space?
Turns out, we can do better. Instead of storing all these numbers, we simply maintain three counters for each of the multiples, namely, 2i, 3j, and 5k. These are candidates for the next number in S. When we pick one of them, we increment only the corresponding counter, and not the other two. By doing so, we are not eagerly generating all the multiples, thus solving the space problem with the first approach.
Let's see a dry run for n = 8, i.e. the number 9. We start with 1, as stated by axiom 1 in Dijkstra's paper.
+---------+---+---+---+----+----+----+-------------------+
| # | i | j | k | 2i | 3j | 5k | S |
+---------+---+---+---+----+----+----+-------------------+
| initial | 1 | 1 | 1 | 2 | 3 | 5 | {1} |
+---------+---+---+---+----+----+----+-------------------+
| 1 | 1 | 1 | 1 | 2 | 3 | 5 | {1,2} |
+---------+---+---+---+----+----+----+-------------------+
| 2 | 2 | 1 | 1 | 4 | 3 | 5 | {1,2,3} |
+---------+---+---+---+----+----+----+-------------------+
| 3 | 2 | 2 | 1 | 4 | 6 | 5 | {1,2,3,4} |
+---------+---+---+---+----+----+----+-------------------+
| 4 | 3 | 2 | 1 | 6 | 6 | 5 | {1,2,3,4,5} |
+---------+---+---+---+----+----+----+-------------------+
| 5 | 3 | 2 | 2 | 6 | 6 | 10 | {1,2,3,4,5,6} |
+---------+---+---+---+----+----+----+-------------------+
| 6 | 4 | 2 | 2 | 8 | 6 | 10 | {1,2,3,4,5,6} |
+---------+---+---+---+----+----+----+-------------------+
| 7 | 4 | 3 | 2 | 8 | 9 | 10 | {1,2,3,4,5,6,8} |
+---------+---+---+---+----+----+----+-------------------+
| 8 | 5 | 3 | 2 | 10 | 9 | 10 | {1,2,3,4,5,6,8,9} |
+---------+---+---+---+----+----+----+-------------------+
Notice that S didn't grow at iteration 6, because the minimum candidate 6 had already been added previously. To avoid this problem of having to remember all of the previous elements, we amend our algorithm to increment all the counters whenever the corresponding multiples are equal to the minimum candidate. That brings us to the following Scala implementation.
def hamming(n: Int): Seq[BigInt] = {
#tailrec
def next(x: Int, factor: Int, xs: IndexedSeq[BigInt]): Int = {
val leq = factor * xs(x) <= xs.last
if (leq) next(x + 1, factor, xs)
else x
}
#tailrec
def loop(i: Int, j: Int, k: Int, xs: IndexedSeq[BigInt]): IndexedSeq[BigInt] = {
if (xs.size < n) {
val a = next(i, 2, xs)
val b = next(j, 3, xs)
val c = next(k, 5, xs)
val m = Seq(2 * xs(a), 3 * xs(b), 5 * xs(c)).min
val x = a + (if (2 * xs(a) == m) 1 else 0)
val y = b + (if (3 * xs(b) == m) 1 else 0)
val z = c + (if (5 * xs(c) == m) 1 else 0)
loop(x, y, z, xs :+ m)
} else xs
}
loop(0, 0, 0, IndexedSeq(BigInt(1)))
}
Basicly the search could be made O(n):
Consider that you keep a partial history of ugly numbers. Now, at each step you have to find the next one. It should be equal to a number from the history multiplied by 2, 3 or 5. Chose the smallest of them, add it to history, and drop some numbers from it so that the smallest from the list multiplied by 5 would be larger than the largest.
It will be fast, because the search of the next number will be simple:
min(largest * 2, smallest * 5, one from the middle * 3),
that is larger than the largest number in the list. If they are scarse, the list will always contain few numbers, so the search of the number that have to be multiplied by 3 will be fast.
Here is a correct solution in ML. The function ugly() will return a stream (lazy list) of hamming numbers. The function nth can be used on this stream.
This uses the Sieve method, the next elements are only calculated when needed.
datatype stream = Item of int * (unit->stream);
fun cons (x,xs) = Item(x, xs);
fun head (Item(i,xf)) = i;
fun tail (Item(i,xf)) = xf();
fun maps f xs = cons(f (head xs), fn()=> maps f (tail xs));
fun nth(s,1)=head(s)
| nth(s,n)=nth(tail(s),n-1);
fun merge(xs,ys)=if (head xs=head ys) then
cons(head xs,fn()=>merge(tail xs,tail ys))
else if (head xs<head ys) then
cons(head xs,fn()=>merge(tail xs,ys))
else
cons(head ys,fn()=>merge(xs,tail ys));
fun double n=n*2;
fun triple n=n*3;
fun ij()=
cons(1,fn()=>
merge(maps double (ij()),maps triple (ij())));
fun quint n=n*5;
fun ugly()=
cons(1,fn()=>
merge((tail (ij())),maps quint (ugly())));
This was first year CS work :-)
To find the n-th ugly number in O (n^(2/3)), jonderry's algorithm will work just fine. Note that the numbers involved are huge so any algorithm trying to check whether a number is ugly or not has no chance.
Finding all of the n smallest ugly numbers in ascending order is done easily by using a priority queue in O (n log n) time and O (n) space: Create a priority queue of numbers with the smallest numbers first, initially including just the number 1. Then repeat n times: Remove the smallest number x from the priority queue. If x hasn't been removed before, then x is the next larger ugly number, and we add 2x, 3x and 5x to the priority queue. (If anyone doesn't know the term priority queue, it's like the heap in the heapsort algorithm). Here's the start of the algorithm:
1 -> 2 3 5
1 2 -> 3 4 5 6 10
1 2 3 -> 4 5 6 6 9 10 15
1 2 3 4 -> 5 6 6 8 9 10 12 15 20
1 2 3 4 5 -> 6 6 8 9 10 10 12 15 15 20 25
1 2 3 4 5 6 -> 6 8 9 10 10 12 12 15 15 18 20 25 30
1 2 3 4 5 6 -> 8 9 10 10 12 12 15 15 18 20 25 30
1 2 3 4 5 6 8 -> 9 10 10 12 12 15 15 16 18 20 24 25 30 40
Proof of execution time: We extract an ugly number from the queue n times. We initially have one element in the queue, and after extracting an ugly number we add three elements, increasing the number by 2. So after n ugly numbers are found we have at most 2n + 1 elements in the queue. Extracting an element can be done in logarithmic time. We extract more numbers than just the ugly numbers but at most n ugly numbers plus 2n - 1 other numbers (those that could have been in the sieve after n-1 steps). So the total time is less than 3n item removals in logarithmic time = O (n log n), and the total space is at most 2n + 1 elements = O (n).
I guess we can use Dynamic Programming (DP) and compute nth Ugly Number. Complete explanation can be found at http://www.geeksforgeeks.org/ugly-numbers/
#include <iostream>
#define MAX 1000
using namespace std;
// Find Minimum among three numbers
long int min(long int x, long int y, long int z) {
if(x<=y) {
if(x<=z) {
return x;
} else {
return z;
}
} else {
if(y<=z) {
return y;
} else {
return z;
}
}
}
// Actual Method that computes all Ugly Numbers till the required range
long int uglyNumber(int count) {
long int arr[MAX], val;
// index of last multiple of 2 --> i2
// index of last multiple of 3 --> i3
// index of last multiple of 5 --> i5
int i2, i3, i5, lastIndex;
arr[0] = 1;
i2 = i3 = i5 = 0;
lastIndex = 1;
while(lastIndex<=count-1) {
val = min(2*arr[i2], 3*arr[i3], 5*arr[i5]);
arr[lastIndex] = val;
lastIndex++;
if(val == 2*arr[i2]) {
i2++;
}
if(val == 3*arr[i3]) {
i3++;
}
if(val == 5*arr[i5]) {
i5++;
}
}
return arr[lastIndex-1];
}
// Starting point of program
int main() {
long int num;
int count;
cout<<"Which Ugly Number : ";
cin>>count;
num = uglyNumber(count);
cout<<endl<<num;
return 0;
}
We can see that its quite fast, just change the value of MAX to compute higher Ugly Number
Using 3 generators in parallel and selecting the smallest at each iteration, here is a C program to compute all ugly numbers below 2128 in less than 1 second:
#include <limits.h>
#include <stdio.h>
#if 0
typedef unsigned long long ugly_t;
#define UGLY_MAX (~(ugly_t)0)
#else
typedef __uint128_t ugly_t;
#define UGLY_MAX (~(ugly_t)0)
#endif
int print_ugly(int i, ugly_t u) {
char buf[64], *p = buf + sizeof(buf);
*--p = '\0';
do { *--p = '0' + u % 10; } while ((u /= 10) != 0);
return printf("%d: %s\n", i, p);
}
int main() {
int i = 0, n2 = 0, n3 = 0, n5 = 0;
ugly_t u, ug2 = 1, ug3 = 1, ug5 = 1;
#define UGLY_COUNT 110000
ugly_t ugly[UGLY_COUNT];
while (i < UGLY_COUNT) {
u = ug2;
if (u > ug3) u = ug3;
if (u > ug5) u = ug5;
if (u == UGLY_MAX)
break;
ugly[i++] = u;
print_ugly(i, u);
if (u == ug2) {
if (ugly[n2] <= UGLY_MAX / 2)
ug2 = 2 * ugly[n2++];
else
ug2 = UGLY_MAX;
}
if (u == ug3) {
if (ugly[n3] <= UGLY_MAX / 3)
ug3 = 3 * ugly[n3++];
else
ug3 = UGLY_MAX;
}
if (u == ug5) {
if (ugly[n5] <= UGLY_MAX / 5)
ug5 = 5 * ugly[n5++];
else
ug5 = UGLY_MAX;
}
}
return 0;
}
Here are the last 10 lines of output:
100517: 338915443777200000000000000000000000000
100518: 339129266201729628114355465608000000000
100519: 339186548067800934969350553600000000000
100520: 339298130282929870605468750000000000000
100521: 339467078447341918945312500000000000000
100522: 339569540691046437734055936000000000000
100523: 339738624000000000000000000000000000000
100524: 339952965770562084651663360000000000000
100525: 340010386766614455386112000000000000000
100526: 340122240000000000000000000000000000000
Here is a version in Javascript usable with QuickJS:
import * as std from "std";
function main() {
var i = 0, n2 = 0, n3 = 0, n5 = 0;
var u, ug2 = 1n, ug3 = 1n, ug5 = 1n;
var ugly = [];
for (;;) {
u = ug2;
if (u > ug3) u = ug3;
if (u > ug5) u = ug5;
ugly[i++] = u;
std.printf("%d: %s\n", i, String(u));
if (u >= 0x100000000000000000000000000000000n)
break;
if (u == ug2)
ug2 = 2n * ugly[n2++];
if (u == ug3)
ug3 = 3n * ugly[n3++];
if (u == ug5)
ug5 = 5n * ugly[n5++];
}
return 0;
}
main();
here is my code , the idea is to divide the number by 2 (till it gives remainder 0) then 3 and 5 . If at last the number becomes one it's a ugly number.
you can count and even print all ugly numbers till n.
int count = 0;
for (int i = 2; i <= n; i++) {
int temp = i;
while (temp % 2 == 0) temp=temp / 2;
while (temp % 3 == 0) temp=temp / 3;
while (temp % 5 == 0) temp=temp / 5;
if (temp == 1) {
cout << i << endl;
count++;
}
}
This problem can be done in O(1).
If we remove 1 and look at numbers between 2 through 30, we will notice that there are 22 numbers.
Now, for any number x in the 22 numbers above, there will be a number x + 30 in between 31 and 60 that is also ugly. Thus, we can find at least 22 numbers between 31 and 60. Now for every ugly number between 31 and 60, we can write it as s + 30. So s will be ugly too, since s + 30 is divisible by 2, 3, or 5. Thus, there will be exactly 22 numbers between 31 and 60. This logic can be repeated for every block of 30 numbers after that.
Thus, there will be 23 numbers in the first 30 numbers, and 22 for every 30 after that. That is, first 23 uglies will occur between 1 and 30, 45 uglies will occur between 1 and 60, 67 uglies will occur between 1 and 30 etc.
Now, if I am given n, say 137, I can see that 137/22 = 6.22. The answer will lie between 6*30 and 7*30 or between 180 and 210. By 180, I will have 6*22 + 1 = 133rd ugly number at 180. I will have 154th ugly number at 210. So I am looking for 4th ugly number (since 137 = 133 + 4)in the interval [2, 30], which is 5. The 137th ugly number is then 180 + 5 = 185.
Another example: if I want the 1500th ugly number, I count 1500/22 = 68 blocks. Thus, I will have 22*68 + 1 = 1497th ugly at 30*68 = 2040. The next three uglies in the [2, 30] block are 2, 3, and 4. So our required ugly is at 2040 + 4 = 2044.
The point it that I can simply build a list of ugly numbers between [2, 30] and simply find the answer by doing look ups in O(1).
Here is another O(n) approach (Python solution) based on the idea of merging three sorted lists. The challenge is to find the next ugly number in increasing order. For example, we know the first seven ugly numbers are [1,2,3,4,5,6,8]. The ugly numbers are actually from the following three lists:
list 1: 1*2, 2*2, 3*2, 4*2, 5*2, 6*2, 8*2 ... ( multiply each ugly number by 2 )
list 2: 1*3, 2*3, 3*3, 4*3, 5*3, 6*3, 8*3 ... ( multiply each ugly number by 3 )
list 3: 1*5, 2*5, 3*5, 4*5, 5*5, 6*5, 8*5 ... ( multiply each ugly number by 5 )
So the nth ugly number is the nth number of the list merged from the three lists above:
1, 1*2, 1*3, 2*2, 1*5, 2*3 ...
def nthuglynumber(n):
p2, p3, p5 = 0,0,0
uglynumber = [1]
while len(uglynumber) < n:
ugly2, ugly3, ugly5 = uglynumber[p2]*2, uglynumber[p3]*3, uglynumber[p5]*5
next = min(ugly2, ugly3, ugly5)
if next == ugly2: p2 += 1 # multiply each number
if next == ugly3: p3 += 1 # only once by each
if next == ugly5: p5 += 1 # of the three factors
uglynumber += [next]
return uglynumber[-1]
STEP I: computing three next possible ugly numbers from the three lists
ugly2, ugly3, ugly5 = uglynumber[p2]*2, uglynumber[p3]*3, uglynumber[p5]*5
STEP II, find the one next ugly number as the smallest of the three above:
next = min(ugly2, ugly3, ugly5)
STEP III: moving the pointer forward if its ugly number was the next ugly number
if next == ugly2: p2+=1
if next == ugly3: p3+=1
if next == ugly5: p5+=1
note: not using if with elif nor else
STEP IV: adding the next ugly number into the merged list uglynumber
uglynumber += [next]

Algorithm for detecting repeating decimals?

Is there an algorithm for figuring out the following things?
If the result of a division is a repeating decimal (in binary).
If it repeats, at what digit (represented as a power of 2) does the repetition start?
What digits repeat?
Some examples:
1/2 = 1/10 = 0.1 // 1 = false, 2 = N/A, 3 = N/A, 4 = N/A
1/3 = 1/11 = 0.010101... // 1 = true, 2 = -2, 3 = 10
2/3 = 10/11 = 0.101010... // 1 = true, 2 = -1, 3 = 10
4/3 = 100/11 = 1.010101... // 1 = true, 2 = 0, 3 = 10
1/5 = 1/101 = 0.001100110011... // 1 = true, 2 = -3, 3 = 1100
Is there a way to do this? Efficiency is a big concern. A description of the algorithm would be preferred over code, but I'll take what answer I can get.
It's also worth noting that the base isn't a big deal; I can convert the algorithm over to binary (or if it's in, say base 256 to use chars for ease, I could just use that). I say this because if you're explaining it might be easier for you to explain in base 10 :).
if the divisor is not a power of 2 (in general, contains prime factors not shared with the base of representation)
repeat cycle length will be driven by the largest prime factor of the dividend (but not connected with the length of the representation of that factor -- see 1/7 in decimal), but the first cycle length may differ from the repeat unit (e.g. 11/28 = 1/4+1/7 in decimal).
the actual cycle will depend on the numerator.
I can give a hint - repeating decimals in base ten are all fraction with the denominator having at least one prime factors other than two and five. If the denominator contains no prime factors two or five, they can always be represented with a denominator of all nines. Then the nominator is the repeating part and the number of nines is the length of the repeating part.
3 _
- = 0.3
9
1 142857 ______
- = ------ = 0.142857
7 999999
If there are prime factors two or five in the denominator, the repeating part starts not at the first position.
17 17 ______
-- = ----- = 0.4857142
35 5 * 7
But I cannot remember how to derive the non-repeating part and its length.
This seem to translate well to base two. Only fraction with a power of two denominator are non-repeating. This can be easily checked by asserting that only a single bit in the denominator is set.
1/2 = 1/10 = 0.1
1/4 = 1/100 = 0.01
3/4 = 11/100 = 0.11
5/8 = 101/1000 = 0.101
All fraction with odd denominators should be repeating and the pattern and its length can be obtained by expressing the fraction with a denominator in the form 2^n-1.
__
1/3 = 1/(2^2-1) = 1/11 = 0.01
__
2/3 = 2/(2^2-1) = 10/11 = 0.10
__
4/3 => 1 + 1/3 => 1.01
__
10/3 => 3 + 1/3 => 11.01
____
1/5 = 3/15 = 3/(2^4-1) = 11/1111 = 0.0011
________
11/17 = 165/255 = 11/(2^8-1) = 10100101/11111111 = 0.10100101
As for base ten, I cannot tell how to handle denominators containing but not being a power of two - for example 12 = 3 * 2^2.
First of all, one of your examples is wrong. The repeating part of 1/5 is 0011 rather than 1100, and it begins at the very beginning of the fractional part.
A repeating decimal is something like:
a/b = c + d(2-n + 2-n-k + 2-n-2k + ...)
= c + 2-n * d / (1 - 2-k)
in which n and d are what you want.
For example,
1/10(dec) = 1/1010(bin) = 0.0001100110011... // 1 = true, 2 = -1, 3 = 0011
could be represented by the formula with
a = 1, b = 10(dec), c = 0, d = 0.0011(bin), n = 1, k = 4;
(1 - 2-k) = 0.1111
Therefore, 1/10 = 0.1 * 0.0011/0.1111. The key part of a repeating decimal representation is generated by dividing by (2n - 1) or its any multiple of 2. So you can either find a way to express your denominator as such (like building constant tables), or do a big number division (which is relatively slow) and find the loop. There's no quick way to do this.
Check out decimal expansion, and specifically about the period of a fraction.
You can do a long division, noting the remainders. The structure of the remainders will give you the structure of any rational decimal:
the last remainder is zero: it is a decimal without any repeating part
the first and the last remainder are equal: the decimal is repeating right after the dot
the distance between the first and the first remainder equal to the last are the non-repeating digits, the remainder is the repeating part
In general the distances will give you the amount of digits for each part.
You can see this algorithm coded in C++ in the method decompose() here.
Try 228142/62265, it has a period of 1776 digits!
To find the repeating pattern, just keep track of the values you use along the line:
1/5 = 1/101:
1 < 101 => 0
(decimal separator here)
10 < 101 => 0
100 < 101 => 0
1000 >= 101 => 1
1000 - 101 = 11
110 >= 101 => 1
110 - 101 = 1
10 -> match
As you reach the same value as you had at the second bit, the process will just repeat from that point producing the same bit pattern over and over. You have the pattern "0011" repeating from the second bit (first after decimal separator).
If you want the pattern to start with a "1", you can just rotate it until it matches that condition:
"0011" from the second bit
"0110" from the third bit
"1100" from the fourth bit
Edit:
Example in C#:
void FindPattern(int n1, int n2) {
int digit = -1;
while (n1 >= n2) {
n2 <<= 1;
digit++;
}
Dictionary<int, int> states = new Dictionary<int, int>();
bool found = false;
while (n1 > 0 || digit >= 0) {
if (digit == -1) Console.Write('.');
n1 <<= 1;
if (states.ContainsKey(n1)) {
Console.WriteLine(digit >= 0 ? new String('0', digit + 1) : String.Empty);
Console.WriteLine("Repeat from digit {0} length {1}.", states[n1], states[n1] - digit);
found = true;
break;
}
states.Add(n1, digit);
if (n1 < n2) {
Console.Write('0');
} else {
Console.Write('1');
n1 -= n2;
}
digit--;
}
if (!found) {
Console.WriteLine();
Console.WriteLine("No repeat.");
}
}
Called with your examples it outputs:
.1
No repeat.
.01
Repeat from digit -1 length 2.
.10
Repeat from digit -1 length 2.
1.0
Repeat from digit 0 length 2.
.0011
Repeat from digit -1 length 4.
As others have noted, the answer involves a long division.
Here is a simple python function which does the job:
def longdiv(numerator,denominator):
digits = []
remainders = [0]
n = numerator
while n not in remainders: # until repeated remainder or no remainder
remainders.append(n) # add remainder to collection
digits.append(n//denominator) # add integer division to result
n = n%denominator * 10 # remainder*10 for next iteration
# Result
result = list(map(str,digits)) # convert digits to strings
result = ''.join(result) # combine list to string
if not n:
result = result[:1]+'.'+result[1:] # Insert . into string
else:
recurring = remainders.index(n)-1 # first recurring digit
# Insert '.' and then surround recurring part in brackets:
result = result[:1]+'.'+result[1:recurring]+'['+result[recurring:]+']'
return result;
print(longdiv(31,8)) # 3.875
print(longdiv(2,13)) # 0.[153846]
print(longdiv(13,14)) # 0.9[285714]
It’s heavily commented, so it shouldn’t be too hard to write in other languages, such as JavaScript.
The most important parts, as regards recurring decimals are:
keep a collection of remainders; the first remainder of 0 is added as a convenience for the next step
divide, noting the integer quotient and the remainder
if the new remainder is 0 you have a terminating decimal
if the new remainder is already in the collection, you have a recurring decimal
repeat, adlib and fade etc
The rest of the function is there to format the results.

Resources