FRQ
› csapa
SelfDivisor: 2007 FRQ 1
A step-by-step solution to the 2007 AP CSA FRQ 1 (SelfDivisor), covering digit extraction with % and /, and building an array of results one match at a time in Java.
Whether every digit of a number evenly divides that same number is the puzzle behind this AP Computer Science A free-response question — first testing a single number, then hunting through consecutive integers to collect a whole array of numbers that pass the test.
What This FRQ Tests
- AP CSA units: Unit 3 (Boolean Expressions and if Statements) and Unit 4 (Iteration)
- Core skill: extracting individual digits from an
intusing%and/, instead of converting the number to aString - Secondary skill: filling an array one element at a time as matching values are found, rather than knowing in advance exactly which values will end up in it
- Official category: "Methods and Control Structures" — always FRQ 1 on the AP CSA exam
The Setup
- No class skeleton beyond two method stubs to fill in on the
SelfDivisorclass:static boolean isSelfDivisor(int number)— isnumbera self-divisor?static int[] firstNumSelfDivisors(int start, int num)— an array of the firstnumself-divisors that are>= start
- A number is a self-divisor if every one of its decimal digits evenly divides the number itself (128 qualifies: it's divisible by 1, 2, and 8).
- A digit of
0automatically disqualifies a number —0is never considered a divisor of anything, so any number containing a0digit fails immediately.
Part (a): Writing isSelfDivisor(int number)
The Rule, Broken Down
- Look at every digit of
number, one at a time. - If any digit is
0, the number is not a self-divisor — stop immediately. - If any digit doesn't evenly divide
number(number % digit != 0), the number is not a self-divisor. - If every digit passes both checks, the number is a self-divisor.
Step-by-Step Approach
- Copy
numberinto a separate loop variable — it needs to shrink as digits get peeled off, but the original value is still needed for every divisibility check. - While that loop variable is still positive, pull off its last digit with
% 10. - Check that digit: if it's
0, or ifnumber % digitisn't0, returnfalseright away. - Otherwise, strip the digit off with integer division by
10, and repeat. - If the loop finishes without ever returning
false, every digit passed — returntrue.
The Code
public static boolean isSelfDivisor(int number)
{
int remaining = number;
while (remaining > 0)
{
int digit = remaining % 10;
if (digit == 0 || number % digit != 0)
{
return false;
}
remaining = remaining / 10;
}
return true;
}
Why Each Piece Matters
remaining % 10— pulls off the current last digit of a number (128 % 10is8).remaining / 10(integer division) — drops that last digit (128 / 10is12), so the next loop pass looks at the digit before it.number % digit, notremaining % digit— the divisibility rule always compares against the original full number; only the digit-peeling itself walks through the shrinkingremainingcopy.digit == 0checked first, with||short-circuiting — this skips ever evaluatingnumber % digitwhendigitis0, which would otherwise throw anArithmeticException(division by zero).
Tracing the Example
128: peel8→128 % 8 == 0✓; peel2→128 % 2 == 0✓; peel1→128 % 1 == 0✓; loop ends → returnstrue, matching the question's own example.26: peel6→26 % 6is2, not0→ returnsfalseimmediately, exactly as the question states ("not evenly divisible by the digit 6"). The digit2is never even reached.105(illustrating the "any0digit disqualifies" rule from the prompt): peel5→105 % 5 == 0✓; peel0→digit == 0is true → returnsfalseimmediately, without ever computing105 % 0.
Common Mistakes to Avoid
- Checking divisibility against
remaininginstead ofnumberon later iterations — after digits have been stripped away,remainingis a smaller, different number, and the rule is specifically about dividing the original number. - Forgetting to special-case a
0digit before computingnumber % digit, which throws anArithmeticExceptioninstead of correctly returningfalse. - Using
remaining >= 0as the loop condition instead ofremaining > 0. Once every real digit has been peeled off, integer division leavesremainingat exactly0. An extra pass with>= 0would then computedigit = 0 % 10, which is0— and thedigit == 0check would incorrectly returnfalsefor every number, self-divisor or not. - Mixing up
%and/— swapping them breaks both the digit-extraction step and the digit-removal step at once.
Part (b): Writing firstNumSelfDivisors(int start, int num)
The Rule, Broken Down
- Search integers starting at
startand counting upward, one at a time. - Test each candidate with
isSelfDivisor— assume it works correctly, regardless of what was written in part (a). - Collect the first
numcandidates that pass, in increasing order, into an array of exactly that size.
Step-by-Step Approach
- Create an
int[]of lengthnumto hold the results. - Track two separate things: how many self-divisors have been found so far (starting at
0), and the current candidate number being tested (starting atstart). - Loop until the results array is completely full.
- Each pass: test the candidate. If it's a self-divisor, store it in the next open array slot and advance the found-count.
- Move to the next integer either way, whether or not the candidate qualified.
- Once the array is full, return it.
The Code
public static int[] firstNumSelfDivisors(int start, int num)
{
int[] result = new int[num];
int count = 0;
int candidate = start;
while (count < num)
{
if (isSelfDivisor(candidate))
{
result[count] = candidate;
count = count + 1;
}
candidate = candidate + 1;
}
return result;
}
Why Each Piece Matters
new int[num]— the array's size is fixed at exactlynumelements up front, since that's the size the method is required to return.count, kept separate fromcandidate— two different counters are needed:candidatewalks upward through every integer in order, butcountonly advances when a self-divisor is actually found, since most candidates won't qualify.candidate = candidate + 1sits outside theif— every candidate gets tested and moved past, whether or not it turned out to be a self-divisor.- Calling
isSelfDivisor(candidate), not re-checking digits here — the question explicitly allows (and expects) reusing the already-specified method rather than duplicating its logic.
Tracing the Example
Using the question's own example, firstNumSelfDivisors(10, 3):
| Candidate | isSelfDivisor? |
Why | Stored at index |
|---|---|---|---|
| 10 | false | contains digit 0 |
— |
| 11 | true | 11 % 1 == 0 twice |
0 |
| 12 | true | 12 % 1 == 0, 12 % 2 == 0 |
1 |
| 13 | false | 13 % 3 is 1 |
— |
| 14 | false | 14 % 4 is 2 |
— |
| 15 | true | 15 % 1 == 0, 15 % 5 == 0 |
2 |
count reaches 3 right after 15 is stored, so the loop stops there. Final result: {11, 12, 15} — matching the question's stated answer exactly.
Common Mistakes to Avoid
- Looping over a fixed range of candidates (e.g.
for (int c = start; c < start + num; c++)) instead of looping untilnumself-divisors are actually found. Self-divisors aren't evenly spaced, so a fixed-size range starting atstartcan easily come up short ofnummatches. - Advancing
counton every iteration, instead of only when a self-divisor is found — this leaves gaps of0(anintarray's default value) inside the result instead of packing matches in order. - Getting the array size wrong — it must be exactly
num, notnum + 1ornum - 1. - Reimplementing the digit-checking logic inline instead of calling
isSelfDivisor. It can produce the same result, but it's exactly the kind of "significant amounts of code that can be replaced by a call to one of these methods" the question's own directions warn may not receive full credit.
Key Takeaways
- Peeling digits off an
intwith% 10and/ 10is the standard pattern for digit-by-digit work — noStringconversion required. - A rule that depends on the whole original number needs every check to reference that original value, never a shrinking copy used for iteration.
- "Find the first
Nresults that satisfy a condition" always needs two independent counters: one that scans every candidate in order, and one that only advances when a match is actually found.