You need to a number of floors in a building. There are 68 floors (numbered 1 to 64).
Conditions:
1. Can’t buy floors which numbers are prime.
2. Cannot buy floors which number contains a prime digit.
3. Can’t buy floor number 1.
4. Distance between all purchased floors must be different (i.e. you can’t buy floors 4, 6, and 8 because they both have 1 floor between them).
5. Distance between all purchased floors must be prime.
Using code or pseudocode figure out:
1. Maximum number of floors you can buy using conditions 1, 2 and 3?
2. Maximum number of floors you can buy using all conditions?
2026 Update: Prime Number Sieves — Segmented Sieve and Prime Counting
Beyond the basic Sieve of Eratosthenes, production-grade prime generation uses the segmented sieve for large ranges, and the Meissel-Mapes-Lehmer formula for prime counting without generation.
def sieve_of_eratosthenes(n: int) -> list:
"""Basic sieve: find all primes up to n. O(n log log n)."""
is_prime = [True] * (n + 1)
is_prime[0] = is_prime[1] = False
for i in range(2, int(n**0.5) + 1):
if is_prime[i]:
for j in range(i*i, n+1, i):
is_prime[j] = False
return [i for i, p in enumerate(is_prime) if p]
def segmented_sieve(low: int, high: int) -> list:
"""
Find all primes in [low, high] using segmented sieve.
Memory: O(sqrt(high)) instead of O(high).
Useful for large ranges where basic sieve doesn't fit in memory.
"""
limit = int(high**0.5) + 1
small_primes = sieve_of_eratosthenes(limit)
segment_size = high - low + 1
is_prime = [True] * segment_size
# Mark multiples of small primes in [low, high]
for p in small_primes:
# First multiple of p that is >= low
start = max(p * p, ((low + p - 1) // p) * p)
for j in range(start, high + 1, p):
is_prime[j - low] = False
# Handle special case: 0 and 1 are not prime
if low == 0:
is_prime[0] = False
if low int:
"""Find the nth prime. Upper bound: n * (ln(n) + ln(ln(n))) for n >= 6."""
import math
if n dict:
gaps = {}
for i in range(1, len(primes)):
gap = primes[i] - primes[i-1]
gaps[gap] = gaps.get(gap, 0) + 1
return dict(sorted(gaps.items()))
primes_1000 = sieve_of_eratosthenes(1000)
gaps = prime_gaps(primes_1000)
print(f"Gap=2 (twin primes to 1000): {gaps.get(2, 0)}") # 35
print(f"Gap=4 (cousin primes to 1000): {gaps.get(4, 0)}") # 16
Segmented sieve advantages: The basic sieve requires O(n) memory. For n = 10^9 (1 billion), that’s 1 GB. The segmented sieve processes [low, high] using only O(√high) memory for the small primes array plus O(segment_size) for the current segment. This enables finding primes in billion-element ranges on machines with limited RAM — used in cryptography for RSA key generation.
💡Strategies for Solving This Problem
Finding Primes Efficiently
Usually one of these: check if number is prime, find all primes up to n, or find nth prime. Each has different tricks. Got this at Google in 2023.
Approach 1: Check If Prime
Naive: Try dividing by all numbers from 2 to n-1. O(n) - too slow.
Better: Only check up to √n. If n has a factor larger than √n, it must also have one smaller than √n.
Even better: Check 2, then only odd numbers up to √n. O(√n).
Approach 2: Find All Primes Up To N
Sieve of Eratosthenes - the classic algorithm.
- Start with all numbers marked as prime
- For each prime p, mark all multiples of p as not prime
- Continue for all p up to √n
O(n log log n) time, O(n) space. Much faster than checking each number individually.
Why Sieve Works
Every composite number has a prime factor ≤ √n. So if we cross out all multiples of primes up to √n, only primes remain.
Optimizations
Start crossing out from p². All smaller multiples already crossed out by smaller primes.
Only store odd numbers (except 2). Saves half the space.
At Google
They asked "Find all primes up to 1 million." I used Sieve of Eratosthenes. Then asked "How would you optimize for space?" That's when I mentioned segmented sieve for very large ranges.
Also asked about primality testing for very large numbers - mentioned Miller-Rabin probabilistic test.