HomeLeetcode264. Ugly Number II - Leetcode Solutions

264. Ugly Number II – Leetcode Solutions

Description

An ugly number is a positive integer whose prime factors are limited to 23, and 5.

Given an integer n, return the nth ugly number.

Examples:

Example 1:

Input: n = 10
Output: 12
Explanation: [1, 2, 3, 4, 5, 6, 8, 9, 10, 12] is the sequence of the first 10 ugly numbers.

Example 2:

Input: n = 1
Output: 1
Explanation: 1 has no prime factors, therefore all of its prime factors are limited to 2, 3, and 5.

Solution in Python

To solve the problem of finding the nth ugly number, we need to compute a sequence where each number has only the prime factors 2, 3, and 5. The basic approach is to generate ugly numbers progressively by multiplying previous ugly numbers by 2, 3, and 5, while ensuring that we avoid duplicates.

Algorithm Overview

  1. Start with the first ugly number: By definition, 1 is considered an ugly number since it has no prime factors.
  2. Use three pointers:
    • p2, p3, and p5 will track the next multiple of 2, 3, and 5, respectively.
    • We initialize these pointers to 0, as we start from the first ugly number in the list, which is 1.
  3. Iteratively generate ugly numbers:
    • At each step, the next ugly number will be the smallest of the numbers generated by multiplying the ugly numbers at p2, p3, and p5 by 2, 3, and 5, respectively.
    • Once we find the smallest candidate, we increment the corresponding pointer (p2, p3, or p5) to ensure that the next candidate for that prime factor is generated.
  4. Avoid duplicates:
    • If multiple pointers generate the same next ugly number, all of the pointers that contribute to this duplicate number are incremented.
Python
class Solution:
    def nthUglyNumber(self, n: int) -> int:
        # We need at least n ugly numbers, so create a list to store them.
        ugly_numbers = [0] * n
        ugly_numbers[0] = 1  # The first ugly number is 1
        
        # Initialize pointers for 2, 3, and 5
        p2, p3, p5 = 0, 0, 0
        
        # Initial multiples for 2, 3, and 5
        next_multiple_of_2 = 2
        next_multiple_of_3 = 3
        next_multiple_of_5 = 5
        
        # Iterate to find all ugly numbers until we reach the nth
        for i in range(1, n):
            # The next ugly number is the minimum of the next multiples
            next_ugly = min(next_multiple_of_2, next_multiple_of_3, next_multiple_of_5)
            
            # Add the smallest found ugly number to the list
            ugly_numbers[i] = next_ugly
            
            # Increment the pointer for whichever factor(s) matched the next ugly number
            if next_ugly == next_multiple_of_2:
                p2 += 1
                next_multiple_of_2 = ugly_numbers[p2] * 2
            if next_ugly == next_multiple_of_3:
                p3 += 1
                next_multiple_of_3 = ugly_numbers[p3] * 3
            if next_ugly == next_multiple_of_5:
                p5 += 1
                next_multiple_of_5 = ugly_numbers[p5] * 5
        
        # The nth ugly number is now at the (n-1)th index of the list (0-based index)
        return ugly_numbers[n - 1]

Detailed Explanation:

  1. Initialization:
    • We start by initializing the first ugly number as 1 (since by definition, 1 is an ugly number).
    • We create three pointers p2, p3, and p5, each starting at index 0. These pointers will be used to keep track of the next position where the multiples of 2, 3, and 5 should be applied.
    • The first multiples of 2, 3, and 5 are initialized as 2, 3, and 5, respectively.
  2. Main Loop:
    • For each number from 1 to n-1, we find the next ugly number by selecting the minimum among next_multiple_of_2, next_multiple_of_3, and next_multiple_of_5.
    • Once the smallest ugly number is found, we increment the corresponding pointer (or pointers) so that the next candidate multiple can be computed. For example, if the next ugly number is from p2, then we move p2 forward and update next_multiple_of_2.
  3. Duplicate Handling:
    • Since it is possible that two or more of the multiples (from 2, 3, and 5) could produce the same ugly number, we ensure that we move all relevant pointers in such cases. This helps avoid adding duplicate ugly numbers.
  4. Final Result:
    • After the loop finishes, the nth ugly number will be stored in the n-1th index of our ugly_numbers list (since indexing starts at 0).

Solution in C++

C++
class Solution {
public:
    int nthUglyNumber(int n) {
        // Create a vector to store the first 'n' ugly numbers
        std::vector<int> ugly_numbers(n);
        
        // The first ugly number is defined as 1
        ugly_numbers[0] = 1;
        
        // Pointers to track the next multiples of 2, 3, and 5
        int p2 = 0, p3 = 0, p5 = 0;
        
        // Initialize the first multiples of 2, 3, and 5
        int next_multiple_of_2 = 2;
        int next_multiple_of_3 = 3;
        int next_multiple_of_5 = 5;
        
        // Start filling the ugly numbers from the second position to the nth
        for (int i = 1; i < n; i++) {
            // The next ugly number will be the minimum of the three multiples
            int next_ugly = std::min(next_multiple_of_2, std::min(next_multiple_of_3, next_multiple_of_5));
            
            // Add the next ugly number to the list
            ugly_numbers[i] = next_ugly;
            
            // If this ugly number was produced by multiplying with 2, increment pointer p2
            if (next_ugly == next_multiple_of_2) {
                p2++;
                next_multiple_of_2 = ugly_numbers[p2] * 2;
            }
            
            // If this ugly number was produced by multiplying with 3, increment pointer p3
            if (next_ugly == next_multiple_of_3) {
                p3++;
                next_multiple_of_3 = ugly_numbers[p3] * 3;
            }
            
            // If this ugly number was produced by multiplying with 5, increment pointer p5
            if (next_ugly == next_multiple_of_5) {
                p5++;
                next_multiple_of_5 = ugly_numbers[p5] * 5;
            }
        }
        
        // The nth ugly number is now at the (n-1)th index (0-based index)
        return ugly_numbers[n - 1];
    }
};

Solution in Javascript

JavaScript
var nthUglyNumber = function(n) {
    // Create an array to store the first 'n' ugly numbers
    let uglyNumbers = new Array(n);
    
    // The first ugly number is defined as 1
    uglyNumbers[0] = 1;
    
    // Initialize three pointers to track the next multiples of 2, 3, and 5
    let p2 = 0, p3 = 0, p5 = 0;
    
    // Initial multiples for 2, 3, and 5
    let nextMultipleOf2 = 2;
    let nextMultipleOf3 = 3;
    let nextMultipleOf5 = 5;
    
    // Fill the array with the first 'n' ugly numbers
    for (let i = 1; i < n; i++) {
        // The next ugly number is the minimum of the three multiples
        let nextUgly = Math.min(nextMultipleOf2, nextMultipleOf3, nextMultipleOf5);
        
        // Add the next ugly number to the array
        uglyNumbers[i] = nextUgly;
        
        // Increment the corresponding pointer(s) to compute the next multiple
        if (nextUgly === nextMultipleOf2) {
            p2++;
            nextMultipleOf2 = uglyNumbers[p2] * 2;
        }
        
        if (nextUgly === nextMultipleOf3) {
            p3++;
            nextMultipleOf3 = uglyNumbers[p3] * 3;
        }
        
        if (nextUgly === nextMultipleOf5) {
            p5++;
            nextMultipleOf5 = uglyNumbers[p5] * 5;
        }
    }
    
    // The nth ugly number is the last element in the array (0-based index)
    return uglyNumbers[n - 1];
};

Solution in Java

Java
class Solution {
    public int nthUglyNumber(int n) {
        // Array to store the first 'n' ugly numbers
        int[] uglyNumbers = new int[n];
        
        // The first ugly number is always 1
        uglyNumbers[0] = 1;
        
        // Initialize three pointers for multiples of 2, 3, and 5
        int p2 = 0, p3 = 0, p5 = 0;
        
        // Initial values for the next multiples of 2, 3, and 5
        int nextMultipleOf2 = 2;
        int nextMultipleOf3 = 3;
        int nextMultipleOf5 = 5;
        
        // Loop to generate the first 'n' ugly numbers
        for (int i = 1; i < n; i++) {
            // The next ugly number is the minimum of the three multiples
            int nextUgly = Math.min(nextMultipleOf2, Math.min(nextMultipleOf3, nextMultipleOf5));
            
            // Store the next ugly number in the array
            uglyNumbers[i] = nextUgly;
            
            // Increment the pointers and update the next multiple as needed
            if (nextUgly == nextMultipleOf2) {
                p2++;
                nextMultipleOf2 = uglyNumbers[p2] * 2;
            }
            if (nextUgly == nextMultipleOf3) {
                p3++;
                nextMultipleOf3 = uglyNumbers[p3] * 3;
            }
            if (nextUgly == nextMultipleOf5) {
                p5++;
                nextMultipleOf5 = uglyNumbers[p5] * 5;
            }
        }
        
        // The nth ugly number is stored in the (n-1)th index (0-based)
        return uglyNumbers[n - 1];
    }
}

Subscribe
Notify of

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Popular