Problem overview
The function sumOfSquares receives a non-negative Int named n and returns 1² + 2² + 3² + ... + n². For n = 3 that is 1 + 4 + 9, which is 14.
Approach: keep a running total
The task is a sum of terms that all follow one pattern, the square of a counter. The standard method is an accumulator:
- start a total at zero;
- visit each number from 1 to
n; - add that number's square to the total;
- return the total when the numbers run out.
That's one pass over n numbers, with a constant amount of memory. A closed formula exists, n * (n + 1) * (2 * n + 1) / 6, but this lesson practises loops, so it builds the sum from the individual squares.
Step by step
- Declare the total.
var sum = 0usesvarbecause the value changes inside the loop. Zero is the right start, since nothing has been added yet. Kotlin infers the typeInt. - Loop from 1 to
n. Usefor (i in 1..n). The..range includes both ends, sonitself gets visited.1 until nwould stop atn - 1. - Add the square. Inside the loop,
sum += i * imultipliesiby itself and adds the product to the total. The operator+=is shorthand forsum = sum + i * i. - Return the total after the loop, when every square has been added.
The solution in Kotlin
class Solution {
fun sumOfSquares(n: Int): Int {
var sum = 0
for (i in 1..n) {
sum += i * i
}
return sum
}
}
Kotlin details to know:
- No power operator. Kotlin has no
**operator for powers. Multiplyingi * iis the simple way. - Empty ranges. If
nis 0, the range1..0is empty. Kotlin ranges only count upward, so the loop does nothing and the function returns 0, which is the correct sum of no terms. - The loop variable.
iis read-only inside the loop body, and the loop supplies the next value on each pass. Intarithmetic is 32-bit. Results past 2,147,483,647 wrap around to negative numbers with no error. This matters here, because squares grow fast (see below).
Tracing n = 3
The table shows the loop for the example.
| i | i * i | sum after the pass |
|---|---|---|
| 1 | 1 | 1 |
| 2 | 4 | 5 |
| 3 | 9 | 14 |
After the third pass the range is used up, the loop ends and the function returns 14. The same code handles any n: only the number of passes changes, never the shape of the work. If a result looks wrong, tracing a tiny input like this one by hand shows which step misbehaves.
Complexity
Time: O(n). The loop runs n times, and each pass does one multiplication and one addition.
Space: O(1). Only sum and the loop variable are stored, whatever the size of n.
Edge cases and common mistakes
n = 0. The result is0, produced by the empty loop.n = 1. The result is1.- Off-by-one in the range.
1 until nleaves outn². Forn = 3it would return 5 instead of 14. - Starting the range at 0. It's harmless, since
0 * 0adds nothing, but it does one pointless pass. - Adding
iinstead ofi * i. That computes1 + 2 + 3 = 6forn = 3, the plain sum. - Overflow. The correct sum for
n = 1860is 2,146,682,110, which just fits in anInt. Forn = 1861the true sum is larger than the maximum, and the function returns the wrapped-around value -2144821865. Forn = 2000it returns -1626300296. Using aLongforsumand the product would delay the problem to much larger inputs.
Testing
n = 3gives14.n = 0gives0.n = 1gives1.n = 10gives385.