Problem overview
The method PrintSeries(int n) prints every value that n takes in the Collatz sequence, starting with n itself and ending at 1. The rules to get the next value are:
- if the current value is even, the next one is half of it;
- if it is odd, the next one is three times the value plus one.
The Collatz conjecture says that, whichever positive integer you start from, this process always reaches 1. Nobody has proven it, but this lesson doesn't need the proof: it only has to run the process and print each value.
For n = 3 the output is 3, 10, 5, 16, 8, 4, 2, 1, one number per line. Starting at 3 (odd) gives 3 * 3 + 1 = 10. Then 10 is even, giving 5, and so on until the sequence reaches 1.
Approach: repeat a rule until a condition holds
The number of steps is not known in advance, so a for loop with a fixed count doesn't fit. A while loop does: it repeats its body as long as a condition is true. Here the condition is n > 1, because the sequence is finished when it reaches 1.
Inside the loop, the current value is replaced by the next one, using an if/else for the two rules, and then the new value is printed. The starting value is printed once, before the loop, because the loop only prints values it has just produced.
Step by step
- Print
nbefore the loop. The series begins with the input value, which no loop pass will produce. - Open a
while (n > 1)loop. The parameternis an ordinary local variable, so the loop can assign new values to it directly. - Handle the even case. When
n % 2 == 0, setn = n / 2. Integer division drops any remainder, which is harmless here becausenis even and the division is exact. - Handle the odd case. In the
elsebranch, setn = 3 * n + 1. - Print the new value, after the
if/elsebut still inside the loop, so it runs for both cases.
The solution in C#
class Solution {
public void PrintSeries(int n) {
Console.WriteLine(n);
while (n > 1) {
if (n % 2 == 0) {
n = n / 2;
} else {
n = 3 * n + 1;
}
Console.WriteLine(n);
}
}
}
Starting at 6, the method prints:
6
3
10
5
16
8
4
2
1
C# details worth knowing:
- Parameters can be reassigned. Arguments are passed by value, so changing
ninside the method changes only the method's own copy. The caller's variable stays the same. - Integer division truncates. With two
intoperands,/produces anint. For example7 / 2is 3. Here the dividend is always even, so nothing is lost. - Return type
void. The method prints, and returns nothing, so it has noreturnstatement. - Overflow wraps. If
3 * n + 1exceeds the maximumintvalue (2,147,483,647), C# wraps around silently to a negative number by default. For a very large starting value this could end the loop early, since a negative number failsn > 1. The lesson's tests use small values, where this does not happen.
Complexity
The running time depends on how many terms the sequence has before it reaches 1, which is not a simple function of n. In practice it is short for small numbers: 27, for example, takes 111 steps. Extra space is O(1), since the method keeps just the current value.
It helps to see why the loop must stop at 1 and not go on. From 1 the odd rule gives 4, then 2, then 1 again, a cycle that would repeat forever. Stopping the moment the value reaches 1 is what makes the loop finite.
Edge cases and common mistakes
n = 1. The method prints 1 and the loop never runs. That is correct: the sequence is already at its end.- Printing in the wrong place. If the print is inside only the
elsebranch, the even values are missing. If it comes before the update instead of after it, the output repeats a value and misses the final 1. - Using
n >= 1. Since 1 is odd, it becomes 4, then 2, then 1, and the loop never ends. - Forgetting to update
n. Writingn / 2without assigning the result leavesnunchanged, and the program loops forever. - Doing the division with a decimal type. Using
doublefornwould print values like5and16the same way, but it invites rounding questions and makes the%test less natural. The sequence only needs whole numbers, sointis the right type.
Testing
n = 3prints 3, 10, 5, 16, 8, 4, 2, 1.n = 1prints just 1.n = 2prints 2, 1.n = 6prints 6, 3, 10, 5, 16, 8, 4, 2, 1.