1234567890 coordinate ---------- +++ range (1,3) ++++++ range (2,7) ++ + range (0,2) ---------- 5557753113 size of smallest window... #### use 5.012; use List::Util qw (min max); my $max_length = 10; my @ranges = ( [ 1, 3 ], [ 2, 7 ], [ 10, 2 ] ); # foreach $i in 1 .. $max_length: $res_a->[$i] == half size of # smallest odd-sized window which is centered at $i and not covered # by any range my $res_a = ranges_a_to_min_uncovered_a(\@ranges); foreach my $i (1 .. $max_length) { print $res_a->[$i]*2+1, " "; # print full size # just to be consistent with the original post # prints '5 5 5 7 7 5 3 1 1 3' } # gets an array of ranges # returns a ref to an arr hich satisfies: # foreach $i in 1 .. $max_length $ret->[$i] == # half size of smallest odd-sized window which is centered at $i and not covered # by any range sub ranges_a_to_min_uncovered_a { my $ranges_a = shift // die; # default value is zero - a coordiante is not covered by any range # arrat length is $max_length+1 since the first position (0) is never used # (coordinates start from 1) my @min_uncovered_window_half_sizes = (0) x ( $max_length + 1 ); foreach my $range ( @{$ranges_a} ) { my $start = $range->[0]; my $end = $range->[1]; # iterate all coordinates in range if ( $start <= $end ) { # simple range for my $i ( $start .. $end ) { ranges_a_to_min_uncovered_a_helper( $i, $range, \@min_uncovered_window_half_sizes ); } } else { # wrapped range for my $i ( $start .. $max_length, 1 .. $end ) { ranges_a_to_min_uncovered_a_helper( $i, $range, \@min_uncovered_window_half_sizes ); } } } # foreach my $range return \@min_uncovered_window_half_sizes; } # gets a range, a coordinate within it and $min_uncovered_a # updates $min_uncovered_a[$coordinate] if needed sub ranges_a_to_min_uncovered_a_helper { my $coordinate = shift // die; my $range = shift // die; my $min_uncovered_a = shift // die; my $dist = min( dist( $range->[0], $coordinate ), dist( $coordinate, $range->[1] ) ); if ( $dist > $min_uncovered_a->[$coordinate] ) { $min_uncovered_a->[$coordinate] = $dist; } } # returns the length covered between $start and $end (both inclusive) sub dist { my $start = shift // die; my $end = shift // die; if ( $end >= $start ) { # simple range return $end - $start + 1; } # warpped range return $max_length - $start + 1 + $end; }