Generating infinite sequences in Kotlin - Time & Space Complexity
When we create infinite sequences, we want to know how the program behaves as it produces more and more items.
We ask: how does the work grow as we take more elements from the sequence?
Analyze the time complexity of the following code snippet.
val infiniteSeq = generateSequence(0) { it + 1 }
fun takeFirstN(n: Int): List {
return infiniteSeq.take(n).toList()
}
This code creates an infinite sequence of numbers starting at 0 and increasing by 1, then takes the first n numbers as a list.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Generating each next number in the sequence and collecting it.
- How many times: Exactly n times, once for each element taken.
Each time we ask for more elements, the program does more work to generate and collect them.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 steps to generate and collect |
| 100 | 100 steps to generate and collect |
| 1000 | 1000 steps to generate and collect |
Pattern observation: The work grows directly with how many elements we take.
Time Complexity: O(n)
This means the time to get n elements grows in a straight line with n; twice as many elements take twice as long.
[X] Wrong: "Since the sequence is infinite, generating elements is instant or constant time."
[OK] Correct: Each element must be created one by one, so the time grows with how many elements you take, not instantly.
Understanding how infinite sequences work helps you think about lazy operations and efficiency in real programs.
"What if we changed the sequence to generate elements by a more complex function? How would the time complexity change?"
Practice
sequence { yield(1); yieldAll(generateSequence(2) { it + 1 }) }Solution
Step 1: Understand sequence behavior
The sequence starts by yielding 1, then continues with an infinite sequence starting at 2, increasing by 1 each time.Step 2: Recognize infinite generation
SincegenerateSequencewith a lambda that adds 1 never returns null, it produces values endlessly.Final Answer:
Generates values endlessly, one at a time, starting from 1 -> Option CQuick Check:
Infinite sequence = endless values [OK]
- Thinking infinite sequences create fixed lists
- Assuming infinite sequences cause errors immediately
- Believing sequences stop after a few values
Solution
Step 1: Identify infinite sequence syntax
generateSequence(seed) { nextValue }creates an infinite sequence by applying the lambda repeatedly.Step 2: Check each option
generateSequence(0) { it + 2 } correctly usesgenerateSequence(0) { it + 2 }to produce even numbers endlessly. Options B and D create finite sequences. generateSequence(0, 2) has incorrect syntax.Final Answer:
generateSequence(0) { it + 2 } -> Option DQuick Check:
Correct syntax = generateSequence(0) { it + 2 } [OK]
- Using sequenceOf for infinite sequences
- Passing two arguments to generateSequence incorrectly
- Not providing a lambda for next values
val seq = generateSequence(1) { it + 3 }
println(seq.take(4).toList())Solution
Step 1: Understand sequence generation
The sequence starts at 1, then each next value adds 3: 1, 4, 7, 10, ...Step 2: Apply take and toList
take(4)takes first 4 values: 1, 4, 7, 10.toList()converts them to a list.Final Answer:
[1, 4, 7, 10] -> Option BQuick Check:
Sequence values = [1,4,7,10] [OK]
- Adding 1 instead of 3 each step
- Confusing take with drop
- Expecting a finite sequence without take
val odds = generateSequence(1) { it + 2 }
println(odds.take(5).toList())Solution
Step 1: Check generateSequence usage
The code usesgenerateSequence(1) { it + 2 }, which correctly generates odd numbers starting at 1.Step 2: Verify output and syntax
take(5).toList()safely takes first 5 odd numbers. No syntax or runtime error exists.Final Answer:
No error; code runs correctly and prints odd numbers -> Option AQuick Check:
Correct infinite sequence = No error; code runs correctly and prints odd numbers [OK]
- Thinking yield is needed inside generateSequence
- Expecting lambda to return null to continue
- Confusing seed value for even numbers
Solution
Step 1: Analyze generateSequence(Pair(0, 1)) { Pair(it.second, it.first + it.second) }.map { it.first }
generateSequence(Pair(0, 1)) { Pair(it.second, it.first + it.second) }.map { it.first } usesgenerateSequencewith pairs to generate Fibonacci pairs, then maps to first element, correctly producing Fibonacci numbers infinitely.Step 2: Analyze sequence { var a=0; var b=1; while(true) { yield(a); val c=a+b; a=b; b=c } }
sequence { var a=0; var b=1; while(true) { yield(a); val c=a+b; a=b; b=c } } uses asequencebuilder with a while(true) loop yielding Fibonacci numbers step-by-step, also correct and infinite.Step 3: Analyze generateSequence(0) { it + it }
generateSequence(0) { it + it } doubles the number each time, not Fibonacci, so it's incorrect.Final Answer:
Both A and B -> Option AQuick Check:
Both methods generate Fibonacci infinite sequences [OK]
- Using generateSequence without pairs for Fibonacci
- Trying to double numbers instead of summing previous two
- Not using yield in sequence builder for infinite values
Ready to prove it?
Pass the test and this pattern moves unknown
