We can simplify this to only the non-constant parts.
num_windows = array.length - window_size + 1
num_windows.times do |i|
window = array.slice(i, window_size)
current_range = window.max - window.min
end
For each element of array
, O(array.length), it looks at a window_size
chunk twice, 2*O(window_size). num_windows
is n, window_size
is m, so that's O(n*m) when array.length is significantly larger than window_size. We'll come back to that.
Perhaps we can see it clearer if we spell out max
and min
longhand.
num_windows = array.length - window_size + 1
# n times
num_windows.times do |i|
# m times, but with a very, very low constant
window = array.slice(i, window_size)
# m times
max = window.each_with_object(nil) { |n,m|
m = n if !m && n > m
}
# m times
min = window.each_with_object(nil) { |n,m|
m = n if !m && n < m
}
current_range = max - min
end
num_windows.times
starts us with O(n) where n = num_windows. Easy.
Each iteration grabs a window_size
, or m, size window
and then window.max
and window.min
have to scan window
twice. That's O(m). Do that n times and it's O(n*m).
As Fabio notes, array.slice(i, window_size)
is also O(m), but it uses memcpy
which has such a low constant it will be totally swamped by window.min
and window.max
. We can ignore it. See https://stackoverflow.com/a/394654/14660 for more.
As a backup, we can plug some numbers in. (I realize I have an off-by-one error here with window_size. It's illustrative to realize that for the purposes of Big-O it doesn't matter. Also I'm lazy and don't want to recalculate.)
array.length = 1000
window_size = 10
num_windows = 990
990 * 2*10 = 19800 # actual
1000 * 10 = 10000 # O(n*m)
The numbers don't have to match, just the ratios as they change. Double the size of array.length, roughly double the cost.
array.length = 2000
window_size = 10
num_windows = 1990
1990 * 2*10 = 39800 # actual
2000 * 10 = 20000 # O(n*m)
Double the size of window_size, roughly double the cost.
array.length = 2000
window_size = 20
num_windows = 1980
1980 * 2*20 = 79200 # actual
2000 * 20 = 40000 # O(n*m)
But as window_size gets close to array.length we get closer to O(n).
array.length = 100
window_size = 99
num_windows = 2
2 * 2*99 = 396 # actual
100 * 99 = 9,900 # O(n*m)
100 = 100 # O(n)
Double the length and double the window_size, O(n*m) says we should be quadrupled. But we only triple which is getting closer to O(n).
array.length = 200
window_size = 198
num_windows = 3
3 * 2*198 = 1188 # actual
200 * 198 = 39600 # O(n*m)
200 = 200 # O(n)