Start learning free

LESSON 165 OF 338 · LOOPS - CHALLENGES

Find Largest Number in Go: Sum of Squares with a Condition-Only for

Practice Read the full explanation

Given a positive number S, find the largest number n such that the sum
12 + 22 + 32 + ... + n2 is less than or equal to S.

For your information, n2 = n * n

Example:

Input: S = 35

Output: 4

Explanation:
12 + 22 + 32 + 42 = 1 + 4 + 9 + 16 = 30
and 30 <= 35
if we add 52 we end up with 55, which exceeds 35
therefore 4 is the answer
Hints:

If we look at the explanation, a simple algorithm comes to mind:
Keep track of the totalSoFar and start iterating from 1 as long as adding number * number to totalSoFar is less than or equal to S.
You continue to add number * number to totalSoFar as long as you don't exceed S
STEP 1 OF 6
    Ctrl + Enter to check

    GO · LOOPS - CHALLENGES

    Find Largest Number in Go, explained

    Problem overview

    The function findLargestNumber receives a positive integer S. It must return the largest n for which the sum 1² + 2² + 3² + ... + n² is less than or equal to S.

    For S = 35: the sums grow as 1, 5, 14, 30 and then 55. The sum for n = 4 is 30, which is at most 35. The sum for n = 5 would be 55, which is over. So the answer is 4.

    Approach: add squares until the next one doesn't fit

    The sum only ever grows, because every square is positive. That means that once adding a square would push the total above S, no larger n can work either. So a single pass is enough: add 1², then 2², then 3², and so on, and stop right before the addition that would exceed S.

    Two variables carry the state: totalSoFar, the sum of the squares added so far, and number, the next number whose square is waiting to be added. The loop condition looks one step ahead, asking whether totalSoFar + number * number is still at most S. If it is, the square is added; if not, the loop ends and totalSoFar never goes over S.

    Step by step

    1. Start the total at 0. Declare totalSoFar with :=. Nothing has been added yet.
    2. Start the counter at 1. Declare number with :=. The sum starts with 1².
    3. Loop on a condition. Go has no while, so use a for with only a condition: continue while totalSoFar + number * number <= S. This checks the next square before adding it.
    4. Add the square of number to totalSoFar with +=.
    5. Move to the next number. Increase number by 1. Without this the condition never changes and the loop doesn't end.
    6. Return number - 1. When the loop stops, number is the first value whose square did not fit. The last value that fit is one less.

    The solution in Go

    func findLargestNumber(S int) int {
        totalSoFar := 0
        number := 1
        for totalSoFar + number * number <= S {
            totalSoFar += number * number
            number += 1
        }
        return number - 1
    }
    

    On S = 35 the loop adds 1, 4, 9 and 16 and reaches number = 5 with totalSoFar = 30. Then 30 + 25 = 55 is more than 35, so the loop stops and the function returns 4.

    Go details worth knowing:

    • Condition-only for. for cond { ... } is Go's while. The condition has no parentheses and is re-evaluated before every iteration, including the first.
    • Operator precedence. In totalSoFar + number * number <= S, multiplication binds tighter than addition, and addition binds tighter than the comparison. No parentheses are needed. gofmt would format this as totalSoFar+number*number <= S; both mean the same.
    • number += 1. Go also has number++, but it is a statement, not an expression. You can't write x = number++ or use it inside a condition.
    • Integers only. All three values are int, so there is no rounding. An int is 64 bits and overflow wraps silently, but a square of the size needed to pass any realistic S is far from that limit.

    Complexity

    The sum of the first n squares is about n³ / 3. For the loop to stop, that sum must exceed S, so the answer n is about the cube root of 3 * S.

    Time: O(S^(1/3)). The loop runs once per value of number, which is the answer plus one, so it runs about the cube root of 3S times. It is sometimes simpler to say it is O(S) at worst, which is true but loose.

    Space: O(1). Two integer variables, whatever the value of S.

    Edge cases and common mistakes

    • Returning number instead of number - 1. After the loop, number is the first value that did not fit. For S = 35 that would be 5, not 4.
    • Checking the total after adding. If the loop added the square first and tested afterwards, the total would overshoot S once before stopping, and the answer would be off by one. Looking ahead in the condition avoids that.
    • Using < instead of <=. When a sum equals S exactly, it is allowed. For S = 5, 1 + 4 = 5 counts, so the answer is 2. With < it would be 1.
    • Small values. For S = 1 the answer is 1. For S = 0, which the task excludes, the loop doesn't run and the function returns 0.
    • Forgetting number += 1. The same square is added again and again, until the total passes S, and the function returns 0. It still ends, but with a wrong answer.

    Testing

    • S = 35 gives 4.
    • S = 1 gives 1.
    • S = 5 gives 2.
    • S = 14 gives 3, since 1 + 4 + 9 = 14 exactly.
    Keep going with GoAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free