Iterate through all positive integers until the count of ugly numbers reaches n; increment the count if the integer is ugly.
To determine if a number is ugly, divide it by the highest powers of 2, 3, and 5 that it is divisible by. If the result is 1, the number is ugly; otherwise, it is not.
For example, to check if 300 is ugly: divide 300 by 4 (highest power of 2) to get 75, then divide 75 by 3 (highest power of 3) to get 25, and finally, divide 25 by 25 (highest power of 5) to get 1. Since the result is 1, 300 is an ugly number.
classSolution {
publicintnthUglyNumber(int n) {
int i = 1;
int count = 1; /* ugly number count */while (n > count) {
i++;
if (isUgly(i)) {
count++;
}
}
return i;
}
privateintisUgly(int no) {
no = maxDivide(no, 2);
no = maxDivide(no, 3);
no = maxDivide(no, 5);
return (no == 1) ? 1 : 0;
}
privateintmaxDivide(int a, int b) {
while (a % b == 0) {
a = a / b;
}
return a;
}
}
Return the last computed ugly number.
The order in which we process the elements would look like:
1
1*2,1*3,2*2,1*5,2*3,3*3,2*5,...
This process is similar to a 3-way merge procedure found in Merge Sort, as we manage three lists sorted by multiplying 2, 3, and 5, and use three pointers to merge these lists. By selecting the smallest value and updating the corresponding pointer, we ensure each minimum value is utilized and avoid duplicates by potentially incrementing more than one pointer at a time.
classSolution {
publicintnthUglyNumber(int n) {
if (n <= 0) {
return 0;
}
int[] ans =newint[n];
ans[0]= 1;
int u = 1; //index for ansint i = 0;
int j = 0;
int k = 0;
while (u < n) {
int m2 = ans[i]* 2;
int m3 = ans[j]* 3;
int m5 = ans[k]* 5;
int min = Math.min(m2, Math.min(m3, m5));
ans[u++]= min;
if (min == m2) {
i++;
}
if (min == m3) {
j++;
}
if (min == m5) {
k++;
}
}
return ans[n - 1];
}
}
1
> I prefer above function for simplicity, but we can avoid recalculating m2, m3 and m5.
As we are again and again getting minimum number, may be minHeap is a good idea.
Below is a straightforward implementation of the idea using a PriorityQueue as a min-heap and a HashSet to track inserted elements and avoid duplicates. The worst-case time complexity is (O(n log n)). It’s important to handle overflow cases when multiplying an ugly number by 2, 3, or 5, as these values can exceed the integer limit. These overflowing values are ignored since they are too large to reach the top of the min-heap.
Of course this is not the fastest solution, but it is also not bad. DP is the best.
Actually min heap’s peek will always have minimum element. So, when we poll out the element, we can check peek of heap is still the same, and just poll them out. So, no need to use set.
⏰ Time complexity: O(n log(n)) - In worst case treeset will have n elements, and adding and removing new elements take log(n) time. So, overall O(n log(n)).