Contiguous arrays and stride tricks in NumPy - Time & Space Complexity
We want to understand how accessing and manipulating contiguous arrays using stride tricks affects the time it takes to run code.
How does the way data is stored and accessed change the work done as the array grows?
Analyze the time complexity of the following code snippet.
import numpy as np
arr = np.arange(1000000)
window_size = 5
# Create a sliding window view using stride tricks
windows = np.lib.stride_tricks.sliding_window_view(arr, window_size)
# Sum each window
result = windows.sum(axis=1)
This code creates overlapping windows of size 5 over a large array and sums each window.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Summing each window of size 5 across the array.
- How many times: The sum operation repeats once for each window, about n - window_size + 1 times.
As the array size grows, the number of windows grows roughly the same as the array length, so the total work grows proportionally.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | ~6 sums of 5 elements each = 30 operations |
| 100 | ~96 sums of 5 elements each = 480 operations |
| 1000 | ~996 sums of 5 elements each = 4980 operations |
Pattern observation: The total operations increase roughly linearly with input size.
Time Complexity: O(n)
This means the time to sum all windows grows in direct proportion to the size of the input array.
[X] Wrong: "Using stride tricks makes the operation constant time regardless of input size."
[OK] Correct: Stride tricks create views without copying data, but summing each window still requires visiting each element, so time grows with input size.
Understanding how data layout and views affect performance helps you write efficient code and explain your choices clearly in interviews.
What if we changed the window size to grow with the input size? How would the time complexity change?
Practice
contiguous?Solution
Step 1: Understand contiguous memory
A contiguous array stores all its elements in one continuous block of memory, which helps with fast access and efficient computation.Step 2: Compare with other options
Options B, C, and D describe other properties unrelated to memory layout.Final Answer:
Its data is stored in one continuous block of memory. -> Option CQuick Check:
Contiguous = continuous memory block [OK]
- Confusing contiguous with array shape
- Thinking contiguous means sorted data
- Assuming contiguous means a copy
Solution
Step 1: Identify stride tricks usage
The functionnp.lib.stride_tricks.as_stridedcreates a view with a new shape and strides without copying data.Step 2: Check other options
Options B, C, and D create copies or flatten arrays, not views with stride tricks.Final Answer:
np.lib.stride_tricks.as_strided(arr, shape=(3,3), strides=(8,8)) -> Option DQuick Check:
Stride tricks use as_strided() [OK]
- Using copy() instead of as_strided()
- Flattening instead of changing strides
- Confusing reshape with stride tricks
import numpy as np arr = np.arange(6) view = np.lib.stride_tricks.as_strided(arr, shape=(3,), strides=(2*arr.itemsize,)) view[0] = 100 print(arr)
Solution
Step 1: Understand stride and view
The view selects elements with stride 2*itemsize, so it accesses arr[0], arr[2], arr[4]. Changing view[0] changes arr[0], changing view[1] changes arr[2], etc.Step 2: Analyze the assignment and print
view[0] = 100 sets arr[0] = 100. The print shows arr with arr[0] changed, arr[2] and arr[4] unchanged.Final Answer:
[100 1 2 3 4 5] -> Option BQuick Check:
Stride view modifies original array [OK]
- Assuming view is a copy, not a view
- Ignoring stride size effect
- Expecting all elements to change
import numpy as np arr = np.arange(4) view = np.lib.stride_tricks.as_strided(arr, shape=(3,3), strides=(8,8)) print(view)
Solution
Step 1: Check shape vs original array size
The original array has 4 elements, but the requested view shape is (3,3) = 9 elements, which is larger than original data.Step 2: Understand stride_tricks constraints
as_strided creates views without copying, so shape must fit within original data size. Here, it does not, causing invalid memory access.Final Answer:
The shape is incompatible with the original array size. -> Option AQuick Check:
View shape must fit original array size [OK]
- Ignoring array size vs view shape
- Assuming as_strided copies data
- Misunderstanding stride meaning
Solution
Step 1: Understand sliding window with stride tricks
Sliding window views use as_strided with shape=(number_of_windows, window_size) and strides that move one element at a time for rows and one element for columns.Step 2: Check options for correct usage
Usenp.lib.stride_tricks.as_stridedwith shape=(len(arr)-3, 4) and strides=(arr.itemsize, arr.itemsize). correctly sets shape and strides to create overlapping windows without copying. Options B and C reshape but do not create sliding windows. Usearr.flatten()and then slice manually. flattens but does not create windows.Final Answer:
Use np.lib.stride_tricks.as_strided with shape=(len(arr)-3, 4) and strides=(arr.itemsize, arr.itemsize). -> Option AQuick Check:
Sliding windows need as_strided with correct shape and strides [OK]
- Using reshape instead of stride tricks
- Copying data unnecessarily
- Incorrect stride values causing wrong windows
Ready to prove it?
Pass the test and this pattern moves unknown
