Ugly numbers are numbers whose only prime factors are 2, 3 or 5. The sequence
1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, …
shows the first 11 ugly numbers. By convention, 1 is included.
Write a program to find and print the 150′th ugly number.
METHOD 1 (Simple)
Thanks to Nedylko Draganov for suggesting this solution.
Algorithm:
Loop for all positive integers until ugly number count is smaller than n, if an integer is ugly than increment ugly number count.
To check if a number is ugly, divide the number by greatest divisible powers of 2, 3 and 5, if the number becomes 1 then it is an ugly number otherwise not.
For example, let us see how to check for 300 is ugly or not. Greatest divisible power of 2 is 4, after dividing 300 by 4 we get 75. Greatest divisible power of 3 is 3, after dividing 75 by 3 we get 25. Greatest divisible power of 5 is 25, after dividing 25 by 25 we get 1. Since we get 1 finally, 300 is ugly number.
Below is the simple method, with printing programme, which can print the ugly numbers:
int maxDivide(int num, int div) { while (num % div == 0) { num /= div; } return num; } bool isUgly(int num) { num = maxDivide(num, 2); num = maxDivide(num, 3); num = maxDivide(num, 5); return num == 1? true:false; } int getNthUglyNo(int n) { int c = 0; int i = 0; while (c < n) { if (isUgly(++i)) c++; } return i; } #include <vector> using std::vector; vector<int> getAllUglyNo(int n) { vector<int> rs; for (int i = 1; i <= n; i++) { if (isUgly(i)) rs.push_back(i); } return rs; }
Dynamic programming:
Watch out: We need to skip some repeated numbers, as commented out below.
Think about this algorithm, conclude as:
We caculate ugly numbers from button up, every new ugly number multiply 2,3,5 respectly would be a new ugly number.
class UglyNumbers { public: int getNthUglyNo(int n, vector<int> &rs) { if (n < 1) return n; int n2 = 2, n3 = 3, n5 = 5; int i2 = 0, i3 = 0, i5 = 0; rs.resize(n, 1); for (int i = 1; i < n; i++) { int t = min(n2, min(n3,n5)); if (t == n2) { rs[i] = n2; n2 = rs[++i2]*2; } if (t == n3) //Watch out, maybe repeated numbers { rs[i] = n3; n3 = rs[++i3]*3; } if (t == n5) //Watch out, no else! { rs[i] = n5; n5 = rs[++i5]*5; } } return rs.back(); } };
Testing:
int main() { unsigned no = getNthUglyNo(35); printf("ugly no. is %d \n", no); vector<int> rs = getAllUglyNo(35); for (auto x:rs) cout<<x<<" "; cout<<endl; UglyNumbers un; printf("Ugly no. is %d \n", un.getNthUglyNo(35, rs)); for (auto x:rs) cout<<x<<" "; cout<<endl; system("pause"); return 0; }