Problem overview
The method IsPrime(int n) returns true when n is a prime number and false otherwise. A prime is an integer greater than 1 whose only divisors are 1 and itself. So 31 is prime, 6 is not (it is divisible by 2 and 3), and neither 0 nor 1 is prime.
The statement sets a budget of O(n) time and O(1) extra space. That is generous enough for the direct approach: try every candidate divisor.
Approach: look for a divisor
A number n is prime exactly when no number d with 1 < d < n divides it. That turns the definition into a search: try each d from 2 up to n - 1, and if any one divides n evenly, n is not prime and the method can answer false immediately. If no d divides n, it is prime.
A number d divides n exactly when the remainder n % d is 0. For 6, the remainder with 2 is 0, so the search stops at the first candidate. For 31, none of 2 to 30 gives remainder 0, so the loop runs to the end.
The search needs to be guarded against small inputs. The definition says primes are greater than 1, but a loop from 2 to n - 1 would not run at all for 0 and 1, and the method would fall through to true. Those numbers are not prime, so they must be handled before the loop.
Step by step
- Reject numbers below 2. If
n < 2, returnfalse. This covers 0 and 1. - Loop over the candidates. Declare
int d = 2and loop whiled < n, increasingdby one each time. The upper limit leaves outnitself, which divides everything trivially. - Test for a divisor. If
n % d == 0, returnfalse. One divisor is enough to rulenout. - Return
trueafter the loop. If the loop ended, no divisor exists.
The solution in C#
class Solution {
public bool IsPrime(int n) {
if (n < 2) {
return false;
}
for (int d = 2; d < n; d++) {
if (n % d == 0) {
return false;
}
}
return true;
}
}
Some C# details:
- The remainder operator
%gives the remainder of integer division, so31 % 2is 1 and6 % 3is 0. - The name is
IsPrime, with aboolreturn type and lowercasetrueandfalse. - The loop starts at 2 and uses
d < n. Forn = 2, the loop condition is false at once, so the loop body never runs and the method returnstrue. That is correct, since 2 is prime. - Each path returns a value. The compiler checks that, and the final
return true;covers the loop finishing.
Tracing 9 and 13
For n = 9: d = 2 gives remainder 1, so the loop continues. d = 3 gives remainder 0, so the method returns false and never tries 4 to 8. For n = 13, every d from 2 to 12 leaves a non-zero remainder, the loop ends, and the method returns true. The two traces show the two ways out of the method: early from inside the loop, or at the end after it.
Complexity
Time: O(n). The loop makes at most n - 2 iterations, each doing one remainder operation. For a composite number the loop usually stops much earlier, at its smallest divisor, but a prime forces the full run.
Space: O(1). The method uses only d.
This is the simplest correct approach, not the fastest one. Any divisor of n larger than its square root is paired with one smaller than it, so checking up to the square root would be enough. That brings the time to O(sqrt(n)), but this lesson stays with the full range.
Edge cases and common mistakes
- 0 and 1. Both are not prime. Without the first
if, they would pass through the loop untouched and be reported as prime. - 2. The smallest prime. It works because the loop body never runs.
- Starting the loop at 1. Every number is divisible by 1, so the method would return
falsefor everything. - Using
d <= n. Every number is divisible by itself, so again every input would be reported as not prime. - Returning
trueinside the loop. If you writeelse { return true; }next to the test, the method decides after checking onlyd = 2. 9 would be reported as prime. The answertrueis only safe after every candidate has been tried. - Large inputs. A big prime such as 2147483647, the largest
int, makes the loop run about two billion times, which is slow. The lesson's tests use modest values.
Why the guard comes first
Placing the n < 2 check before the loop keeps the loop simple. The loop only has to reason about numbers that are at least 2, where "has a divisor between 2 and n - 1" is exactly the same as "is not prime". Folding the special cases into the loop would make the loop harder to read and easier to get wrong.
Testing
31givestrue.6givesfalse.2givestrue, and3givestrue.1and0both givefalse.9givesfalse, and25givesfalse: squares of primes are a good test for the loop.