File: ugly-number/solution.py

Date: 2026-06-06

Time: 19:34

ugly-number/solution.py

Purpose

This file implements LeetCode #263 — Ugly Number. It owns the single responsibility of determining whether an integer qualifies as an "ugly number" — a positive integer whose only prime factors are 2, 3, and 5. The numbers 1, 2, 3, 4, 5, 6, 8, 10, 12, 15... are ugly; 7, 11, 13, 14... are not.

Key Components

is_ugly(n: int) -> bool — The sole public function. Contract:

Patterns

Trial division with exhaustive factor removal. Rather than factoring n completely and checking the factor set, the code takes the inverse approach: strip away all allowed factors (2, 3, 5) and check if anything remains. If n reduces to 1, every prime factor was in {2, 3, 5}. If not, some disallowed prime divides n.

This is the canonical pattern for this class of problem — it avoids explicit primality testing or full factorization.

Dependencies

Imports: None. Pure Python, no standard library usage.

Imported by: The ugly-number/testsolution.py file directly. The "Imported By" list in the prompt is misleadingly long — those are unrelated test files that happen to share the same test runner infrastructure, not actual consumers of isugly.

Flow

1. Guard: reject non-positive inputs immediately (n <= 0 → False). This handles zero and negative numbers in one check.

2. Factor stripping loop: iterate over the tuple (2, 3, 5). For each prime p, divide n by p repeatedly until p no longer divides n. This is an inner while loop nested inside a for loop — O(log n) total divisions across all three primes.

3. Residual check: if n == 1, all prime factors were stripped away, so n was ugly. Any residual > 1 means a prime factor outside {2, 3, 5} exists.

Invariants

Error Handling

None. The function handles all edge cases via its return value — there are no exceptions, assertions, or sentinel values. Invalid inputs (non-positive integers) return False, which aligns with the LeetCode problem spec.

Topics to Explore

Beliefs