Блог пользователя code_fille

Автор code_fille, история, 9 лет назад, По-английски

Given an array of integers and a range find the count of subarrays whose sum lies in the given range. Do so in less than O(n^2) complexity.

  • Проголосовать: нравится
  • +5
  • Проголосовать: не нравится

»
9 лет назад, # |
Rev. 6   Проголосовать: нравится +10 Проголосовать: не нравится

let us call the range [ l, r ] build the prefix sum array for the given array, let us call it B (B[0]=0 for empty prefix)

now
B[i] - B[j] where 0 ≤ j < i
gives all the sums of subarrays that end in ith element

So, in order for the sum of subarray [ j + 1...i ] to be between l and r the following should be true:

l ≤ B[i] - B[j] ≤ r
=>
l - B[i] ≤  - B[j] ≤ r - B[i]
=>
B[i] - l ≥ B[j] ≥ B[i] - r

so for each B[i], we should find the number of B[j] s that are in the previous range and j < i, which is done in a segment tree

total complexity: O(nlogn)

NOTE If the values are all positive you can use binary search for O(nlogn)

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    How could segment tree be used to find the possible values of j?

    • »
      »
      »
      9 лет назад, # ^ |
      Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

      Array C , C[i] is the number of B[j]'s which are equal to i
      You need a segment tree to perform 2 types of queries:
      1) add 1 to C[x]
      2) get the sum of C[x] : s<=x<=e

      So for each B[i] you query for the sum of C[x] between B[i]-r and B[i]-l Then you add 1 to C[B[i]]

  • »
    »
    9 лет назад, # ^ |
    Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

    If the values are all positive you can solve in O(N) using only 3 pointers.

    Note: You can also solve in O(NlogN) without segment tree, just using divide-and-conquer idea.

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Could you elaborate how divide and conquer could be used?

      • »
        »
        »
        »
        9 лет назад, # ^ |
        Rev. 3   Проголосовать: нравится 0 Проголосовать: не нравится

        B — partial sum, B[0] = 0.

        Now we are going to split our verctor a into 2 parts with size N / 2 each.

        2 cases are possible:

        1) l, r < N / 2 or l, r > N / 2: We can find the answer recursively for the left part and for the right part.

        2) l < N / 2 and r > N / 2: We can find the answer in O(N) using 3 pointers but only if the left part sorted and the right part sorted too. But you can maintain these parts sorted by using merge sort algorithm.

        The algorithm is very similar to the algorithm for counting inversions in O(NlogN) time. You can find the explanation on coursera: link

  • »
    »
    8 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    For segment tree , Is the time complexity is (n*log(sum of all array elements)) ? correct me if i am wrong.

  • »
    »
    6 лет назад, # ^ |
      Проголосовать: нравится +8 Проголосовать: не нравится

    Your solution is quite beautiful :)