Problem overview
The method printSeries takes an integer n and prints every value of the Collatz sequence that starts at n. Each term comes from the previous one: if it is even, the next term is half of it; if it is odd, the next term is three times it plus one. The sequence stops when it reaches 1, which the conjecture says always happens for positive starting values.
For n = 3 the output is 3, 10, 5, 16, 8, 4, 2, 1, one number per line. The starting value is printed too, and so is the final 1.
Approach: repeat until the value reaches 1
The number of steps isn't known in advance, so a while loop fits better than a for loop. The loop keeps going as long as the current value is greater than 1, and each pass applies one of the two rules and prints the result. The starting value is printed before the loop, since the loop prints only the values it produces.
The current value changes, so it must live in a variable. Swift's function parameters are constants, so n itself can't be updated, and the method copies it into a variable first.
Tracing n = 6
The method prints 6 first. The loop sees 6 > 1, 6 is even, so num becomes 3 and 3 is printed. Next, 3 is odd, so num becomes 10 and 10 is printed. Then come 5, 16, 8, 4 and 2. When num becomes 1 it is printed, and the loop condition 1 > 1 is false, so the method ends. The 1 is printed because the print comes right after the update, before the condition is checked again.
Step by step
- Copy the parameter into a variable.
var num = ncreates a changeable value. Withlet, or by assigning tondirectly, the compiler reports that the value is a constant. - Print the starting value. It is the first number of the sequence.
- Write
while num > 1. Testnum, notn: onlynumchanges in the loop body, so a condition onnwould never change. - Handle the even case. If
num % 2 == 0, setnum = num / 2. Dividing twoIntvalues drops any remainder, and for an even number there is none. - Handle the odd case in the
elsebranch:num = 3 * num + 1. - Print
numafter theif/else, still inside the loop, so every new term is printed whichever rule produced it.
The solution in Swift
class Solution {
func printSeries(_ n: Int) {
var num = n
print(num)
while num > 1 {
if num % 2 == 0 {
num = num / 2
} else {
num = 3 * num + 1
}
print(num)
}
}
}
Swift details worth knowing:
varversuslet.vardeclares something you can reassign. Parameters behave likelet, which is why the copy is needed.- Integer division.
/betweenIntvalues gives anIntand truncates toward zero:7 / 2is 3. It is exact here only because the branch handles even numbers. - No parentheses around conditions, but the braces are mandatory.
- Overflow traps.
Intis 64 bits, and arithmetic that overflows crashes the program instead of wrapping. Sequences from ordinary starting values stay far from that limit: starting at 27, the sequence takes 111 steps and peaks at 9232.
Why the output can look surprising
The sequence doesn't shrink steadily. Small starting values can climb well above where they began before falling: 3 reaches 16, and 27 climbs to 9232 before it finally comes down to 1. Printing every term shows that rise and fall, and it is why the loop must test the current value rather than count down from n.
Complexity
The running time depends on the length of the sequence, and nobody has proved a bound for it, since the conjecture itself is unproven. For any starting value you can actually try, the sequence ends, and the loop does a constant amount of work per term. The space is O(1): a single variable.
Edge cases and common mistakes
- Starting at 1. The method prints 1 and the loop doesn't run.
- Starting at 0 or below. The condition
num > 1is false immediately, so only the starting value is printed. 0 and negative numbers are outside the problem, and the loop is not entered for them. - Printing the start twice or not at all. The start is printed before the loop, and only new terms inside it.
- Printing inside only one branch. The final
print(num)must come after theelseblock, or half the terms are missing. - A loop condition on
n. It would never become false, so the program would never stop.
Testing
printSeries(3)prints 3, 10, 5, 16, 8, 4, 2, 1.printSeries(6)prints 6, 3, 10, 5, 16, 8, 4, 2, 1.printSeries(1)prints 1.
