Skip to content

Commit 7dd6bce

Browse files
Merge pull request #8 from theforestvn88/august
1508
2 parents 40471f0 + 90ce830 commit 7dd6bce

File tree

1 file changed

+109
-0
lines changed

1 file changed

+109
-0
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# @param {Integer[]} nums
2+
# @param {Integer} n
3+
# @param {Integer} left
4+
# @param {Integer} right
5+
# @return {Integer}
6+
def range_sum(nums, n, left, right)
7+
sums = []
8+
(0...nums.size).each { |i|
9+
sum = 0
10+
(i...nums.size).each { |j|
11+
sum += nums[j]
12+
sums << sum
13+
}
14+
}
15+
16+
sums.sort!
17+
18+
mod = 1000000007
19+
sum = 0
20+
(left-1..right-1).each { |i|
21+
sum = (sum + sums[i]) % mod
22+
}
23+
24+
sum
25+
end
26+
27+
28+
# binary-search approach
29+
# O(nlogn)
30+
def range_sum(nums, n, left, right)
31+
# count on sum-array which computed the sum of all non-empty continuous subarrays from the array
32+
count_sub_arrays_have_sum_less_than_or_equal = lambda { |max_sum|
33+
count = 0
34+
total_sum = 0 # sum of all sum of sub-arrays <= max_sum
35+
window_sum = 0 # maintain the window [i..j] that has sum <= max_sum
36+
total_window_sum = 0 # sum of all sum of sub-arrays (in window) <= max_sum
37+
i = j = 0
38+
while j < nums.size
39+
# for each new j
40+
# ..i.....[j]
41+
# [ ] <----- all of them is counted into total_window_sum at previous j
42+
# [ ] <----- now with new j, we can calculate total_window_sum
43+
# [ ] <----- by adding nums[j] for each of them
44+
# ... <-----
45+
total_window_sum += nums[j] * (j-i+1)
46+
# extend window
47+
window_sum += nums[j]
48+
# adjust windown [i..j] so the sum <= max_sum by shift-right i
49+
while window_sum > max_sum
50+
# each time we shift-right i by 1
51+
# ...i......j
52+
# x[ ] <--- remove i+1
53+
# x[ ] <--- remove i+2
54+
# x[ ] <--- remove i+3
55+
# ..... <--- and so on ... so we end up removing window_sum
56+
total_window_sum -= window_sum
57+
window_sum -= nums[i]
58+
i += 1
59+
end
60+
61+
total_sum += total_window_sum
62+
count += j-i+1 # for each window [i..j], we have j-i+1 sub-arrays
63+
j += 1
64+
end
65+
66+
[count, total_sum]
67+
}
68+
69+
min = nums.min
70+
max = nums.sum
71+
72+
# suppose sum-array is sorted, all values will be in range [min..max]
73+
# we can find sum-array[i] by binary-searching in [min..max] which max-value that
74+
# the number of {sum-sub-array <= value} is >= i + 1
75+
# ......value......
76+
# ......i
77+
#[i+1 sum]
78+
#
79+
# sum of sum-array[0..index]
80+
find_sum_to_index = lambda { |index| # 0-indexed
81+
low = min
82+
high = max
83+
84+
while low < high
85+
m = (low + high)/2
86+
count, sum = count_sub_arrays_have_sum_less_than_or_equal.call(m)
87+
if count < index + 1
88+
low = m + 1
89+
else
90+
high = m
91+
end
92+
end
93+
94+
# now low is the max-value we need to find
95+
# since we count all sums that <= low, so there're some dup lows
96+
# we need to cut them
97+
# .....low low low ....
98+
# .....index....count
99+
# [ ]---------
100+
count, sum = count_sub_arrays_have_sum_less_than_or_equal.call(low)
101+
sum - low * (count - index - 1)
102+
}
103+
104+
# 0-indexed
105+
# .... left-2 .... right-1 ....
106+
# [ ]
107+
# [ |-----------]
108+
(find_sum_to_index.call(right-1) - find_sum_to_index.call(left-2)) % 1000000007
109+
end

0 commit comments

Comments
 (0)