Problem overview
The method isPrime receives a non-negative integer n and returns true if it is prime and false if it is not. A prime number is greater than 1 and divisible only by 1 and itself. For n = 31 the answer is true. For n = 6 the answer is false, because 6 is divisible by 2 and 3.
The statement asks for O(n) time and O(1) extra space. That tells you a plain loop that tries the possible divisors one by one is acceptable, and that you should not store anything proportional to n.
Approach: look for a divisor
The definition is about divisors, so it is easier to turn it around. A number n is prime exactly when it is at least 2 and there is no number d with 1 < d < n that divides it evenly. Checking for the absence of something is a familiar pattern: search for a counterexample, and if you find one, answer false immediately. If the search ends without finding one, the answer is true.
The candidates for d are 2, 3, ..., n - 1. A number d divides n when the remainder of n / d is zero, which TypeScript writes as n % d === 0.
That takes about n - 2 remainder checks in the worst case, which is the O(n) the statement asks for. Faster methods exist, such as stopping the search at the square root of n, but this lesson uses the simplest version.
Numbers below 2 need their own rule, since the definition excludes them: 0 and 1 are not prime.
Step by step
- Reject the numbers below 2. Test
n < 2first and returnfalse. This covers 0 and 1. The loop would not run for either of them, so without this line the method would wrongly returntrue. - Loop over the candidate divisors. A
forloop with the variabledstarts at 2 and runs whiled < n, so the last value isn - 1. Starting at 1 would be wrong, since every number is divisible by 1, and includingnwould be wrong for the same reason. - Test divisibility. Inside the loop, if
n % d === 0, thenddividesn, andnis not prime. Returnfalseright away, which ends the whole method. - Return
trueat the end. If the loop finishes, no divisor was found, sonis prime. Forn = 2the loop does not run at all, and forn = 3its only pass finds that 2 does not divide 3, so both correctly end up here.
The solution in TypeScript
class Solution {
isPrime(n: number): boolean {
if (n < 2) {
return false;
}
for (let d = 2; d < n; d++) {
if (n % d === 0) {
return false;
}
}
return true;
}
}
Some TypeScript details about this code:
- One numeric type. There is no separate integer type, so
nanddare bothnumber, a double-precision floating-point value. The code relies on the input being a whole number. CallingisPrime(2.5)returnstruein this code, because2.5 % 2is 0.5 and the loop ends atd = 3. The annotationn: numberdoes not rule decimals out, and nothing is checked at run time. - The remainder operator.
%works on numbers and returns the remainder with the sign of the left operand. For a non-negativenand a positivedthe result is never negative, so comparing with 0 is safe. - Strict equality.
===compares without converting types. It is the comparison to use in TypeScript. - No overflow. A
numberkeeps integers exact up to2^53, which is far beyond what a loop of this kind can reasonably reach, so there is no wrap-around to worry about. - The loop variable is local.
let dexists only inside theforstatement, and the name is not visible after the loop ends.
Complexity
Time: O(n). The loop runs at most n - 2 times, and each pass does one remainder and one comparison. For a composite number it often stops much earlier, since the smallest divisor ends the search. Primes are the worst case, because they run the whole loop.
Space: O(1). The method uses only the variables n and d.
Edge cases and common mistakes
- 0 and 1 are not prime. The guard at the top handles them. Both give
false. - 2 is prime. It is the only even prime. With
n = 2the loop starts atd = 2and the conditiond < nis already false, so the method returnstrue. - Starting the loop at 1. Every number gives remainder 0 when divided by 1, so every number would be reported as not prime.
- Looping up to and including
n. Every number is also divisible by itself, which leads to the same wrong answer. - Returning
trueinside the loop. Finding onedthat does not dividensays nothing about the others. Only the end of the loop proves there is no divisor. - Using
/for the test. In TypeScript,6 / 4is1.5, not a whole number with a remainder. Divisibility is tested with%. - Negative input. The task promises non-negative values, but the guard also makes
-7returnfalse.
Testing
n = 31givestrue, andn = 6givesfalse.n = 0andn = 1givefalse.n = 2andn = 3givetrue.n = 9givesfalse, andn = 97givestrue.n = 100givesfalse.