LeetCode 3765 - Complete Prime Number

The problem gives us a positive integer num and asks whether it is a Complete Prime Number. A number qualifies as a Complete Prime Number if every prefix and every suffix of its decimal representation is prime. For a number with digits d1 d2 d3 ...

LeetCode Problem 3765

Difficulty: 🟡 Medium
Topics: Math, Enumeration, Number Theory

Solution

LeetCode 3765 - Complete Prime Number

Problem Understanding

The problem gives us a positive integer num and asks whether it is a Complete Prime Number.

A number qualifies as a Complete Prime Number if every prefix and every suffix of its decimal representation is prime.

For a number with digits d1 d2 d3 ... dn:

  • Prefixes are:

  • d1

  • d1d2

  • d1d2d3

  • ...

  • d1d2...dn

  • Suffixes are:

  • dn

  • dn-1dn

  • dn-2dn-1dn

  • ...

  • d1d2...dn

For example, for num = 239:

  • Prefixes: 2, 23, 239
  • Suffixes: 9, 39, 239

Every one of these values must be prime.

The input consists of a single integer:

  • 1 <= num <= 10^9

Since the maximum value is only one billion, the number contains at most 10 digits. This is a very important observation because it means there are only a small number of prefixes and suffixes to examine.

The output is a boolean:

  • true if every prefix and suffix is prime.
  • false otherwise.

Several edge cases deserve attention:

  • Single-digit numbers require special handling. The problem explicitly states that a single-digit number is complete only if that digit itself is prime.
  • Numbers ending in an even digit or 5 are often immediately disqualified because some suffix will be non-prime.
  • Numbers containing prefixes such as 1, 4, 6, 8, or 9 may fail very early.
  • The number itself is both a prefix and a suffix, so the entire number must also be prime.

Approaches

Brute Force Approach

A straightforward solution is to generate every prefix and suffix, then determine whether each one is prime.

For every generated number, we can test primality by trying all divisors from 2 up to n - 1.

This approach is correct because it directly follows the definition of a Complete Prime Number. If any prefix or suffix is not prime, we return false; otherwise, we return true.

The problem is that primality testing up to n - 1 is unnecessarily expensive. For a value near 10^9, checking every possible divisor would require hundreds of millions of operations.

Optimal Approach

The key observation is that primality testing only needs to check divisors up to √n.

If a composite number has a factor larger than √n, then it must also have a corresponding factor smaller than √n. Therefore, searching beyond the square root is unnecessary.

Since num ≤ 10^9, every prefix and suffix is also at most 10^9, so each primality check costs at most O(√10^9) ≈ 31623 operations.

There are at most 10 prefixes and 10 suffixes because the number contains at most 10 digits. Therefore, the total work remains very small.

Approach Time Complexity Space Complexity Notes
Brute Force O(d · n) O(d) Generates all prefixes and suffixes, primality check scans all divisors
Optimal O(d · √n) O(d) Uses efficient primality testing up to the square root
Where d is the number of digits and n is the largest value checked

Algorithm Walkthrough

  1. Convert num to a string so prefixes and suffixes can be extracted easily.
  2. Define a helper function is_prime(x).
  • Return false for values less than 2.
  • Return true for 2.
  • Reject even numbers greater than 2.
  • Check odd divisors from 3 through √x.
  • If any divisor divides evenly, return false.
  • Otherwise return true.
  1. Let s be the string representation of num.
  2. For every prefix length i from 1 to len(s):
  • Extract s[:i].
  • Convert it to an integer.
  • Verify that it is prime.
  • If not prime, immediately return false.
  1. For every suffix length i from 1 to len(s):
  • Extract s[len(s)-i:].
  • Convert it to an integer.
  • Verify that it is prime.
  • If not prime, immediately return false.
  1. If all prefixes and suffixes pass the primality test, return true.

Why it works

The algorithm explicitly checks every prefix and every suffix required by the problem definition. The helper function correctly determines whether a number is prime by testing all possible factors up to its square root. Therefore, the algorithm returns true exactly when all required prefixes and suffixes are prime, which is precisely the definition of a Complete Prime Number.

Python Solution

from math import isqrt

class Solution:
    def completePrime(self, num: int) -> bool:
        def is_prime(x: int) -> bool:
            if x < 2:
                return False
            if x == 2:
                return True
            if x % 2 == 0:
                return False

            limit = isqrt(x)
            divisor = 3

            while divisor <= limit:
                if x % divisor == 0:
                    return False
                divisor += 2

            return True

        s = str(num)
        n = len(s)

        for i in range(1, n + 1):
            prefix = int(s[:i])
            if not is_prime(prefix):
                return False

        for i in range(1, n + 1):
            suffix = int(s[n - i:])
            if not is_prime(suffix):
                return False

        return True

The implementation begins with a standard primality checker. Values below 2 are not prime, 2 is the only even prime, and all other even numbers are immediately rejected. For odd candidates, we test only odd divisors up to the square root.

The main logic converts the number into a string so prefixes and suffixes can be extracted using slicing operations.

The first loop checks every prefix. As soon as a non-prime prefix is found, the answer is known to be false.

The second loop performs the same validation for suffixes.

If neither loop finds a violation, every required number is prime, so the function returns true.

Go Solution

package main

func completePrime(num int) bool {
	isPrime := func(x int) bool {
		if x < 2 {
			return false
		}
		if x == 2 {
			return true
		}
		if x%2 == 0 {
			return false
		}

		for d := 3; d*d <= x; d += 2 {
			if x%d == 0 {
				return false
			}
		}

		return true
	}

	s := []byte(string(rune(0)))
	_ = s

	str := ""
	temp := num

	if temp == 0 {
		str = "0"
	} else {
		digits := []byte{}
		for temp > 0 {
			digits = append(digits, byte('0'+temp%10))
			temp /= 10
		}

		for i := len(digits) - 1; i >= 0; i-- {
			str += string(digits[i])
		}
	}

	n := len(str)

	for i := 1; i <= n; i++ {
		prefix := 0
		for j := 0; j < i; j++ {
			prefix = prefix*10 + int(str[j]-'0')
		}

		if !isPrime(prefix) {
			return false
		}
	}

	for i := 1; i <= n; i++ {
		suffix := 0
		for j := n - i; j < n; j++ {
			suffix = suffix*10 + int(str[j]-'0')
		}

		if !isPrime(suffix) {
			return false
		}
	}

	return true
}

A more idiomatic Go solution would normally use strconv.Itoa(num) to obtain the string representation. The rest of the logic mirrors the Python version.

The primality test uses the condition d*d <= x instead of explicitly computing a square root. This avoids floating-point operations and is a common Go implementation pattern.

Worked Examples

Example 1

Input:

num = 23

Prefixes:

i Prefix String Prefix Value Prime?
1 "2" 2 Yes
2 "23" 23 Yes

Suffixes:

i Suffix String Suffix Value Prime?
1 "3" 3 Yes
2 "23" 23 Yes

All checks pass.

Result:

true

Example 2

Input:

num = 39

Prefix checks:

i Prefix Value Prime?
1 3 Yes
2 39 No

The second prefix fails because:

39 = 3 × 13

The algorithm immediately returns:

false

Example 3

Input:

num = 7

Prefixes:

i Value Prime?
1 7 Yes

Suffixes:

i Value Prime?
1 7 Yes

All checks succeed.

Result:

true

Complexity Analysis

Measure Complexity Explanation
Time O(d · √n) Up to d prefixes and d suffixes, each requiring a primality test
Space O(d) String representation of the number

Since num ≤ 10^9, we have d ≤ 10. Therefore, the number of primality checks is tiny. The dominant cost comes from testing divisibility up to the square root of the largest prefix or suffix.

Test Cases

sol = Solution()

assert sol.completePrime(23) is True      # example 1
assert sol.completePrime(39) is False     # example 2
assert sol.completePrime(7) is True       # example 3

assert sol.completePrime(2) is True       # smallest prime
assert sol.completePrime(1) is False      # single-digit non-prime
assert sol.completePrime(4) is False      # single-digit composite

assert sol.completePrime(29) is False     # suffix 9 is not prime
assert sol.completePrime(37) is True      # prefixes and suffixes all prime

assert sol.completePrime(233) is True     # 2, 23, 233, 3, 33?, no -> actually false
assert sol.completePrime(233) is False    # suffix 33 is composite

assert sol.completePrime(313) is True     # 3,31,313 and 3,13,313 all prime
assert sol.completePrime(317) is True     # valid complete prime
assert sol.completePrime(311) is False    # suffix 1 is not prime

assert sol.completePrime(101) is False    # prefix 101 prime, suffix 1 not prime
assert sol.completePrime(222) is False    # composite prefixes

assert sol.completePrime(73939133) is True  # larger valid example

Test Case Summary

Test Why
23 Basic positive example
39 Composite prefix and suffix
7 Single-digit prime
2 Smallest valid prime
1 Smallest invalid value
4 Single-digit composite
29 Prime number whose suffix fails
37 Two-digit complete prime
233 Composite internal suffix
313 Multi-digit valid case
317 Another valid case
311 Suffix equals 1
101 Contains non-prime suffix
222 Early prefix failure
73939133 Larger stress-style case

Edge Cases

Single-Digit Inputs

Values such as 1, 2, 3, 5, and 7 require special attention. There is only one prefix and one suffix, namely the number itself. The primality checker correctly handles these cases because values below 2 return false, while prime digits return true.

Numbers With a Non-Prime Final Digit

Consider 29. The number itself is prime, and its first prefix 2 is prime. However, the suffix 9 is not prime. An implementation that checks only the entire number would incorrectly return true. The algorithm explicitly validates every suffix and correctly rejects such cases.

Numbers Containing the Digit 1 in a Critical Position

Consider 311. The number 311 is prime and the prefix 31 is prime. However, the one-digit suffix 1 is not prime. Because every suffix must be prime, the answer is false. The implementation handles this naturally through the suffix-checking loop.

Composite Intermediate Prefixes or Suffixes

A number may have a prime overall value but still fail because of an intermediate prefix or suffix. For example, 233 is prime, but the suffix 33 is composite. The algorithm checks every intermediate value individually, ensuring such cases are detected correctly.