https://leetcode-cn.com/problems/count-of-range-sum/

https://leetcode-cn.com/problems/count-of-range-sum/

 

 

 套例子:

     0   1    2  3

  arr[ 1, -1, -2, 3]                       范围[ -1, 1 ]

暴力解法:

0-0 [ 1 ]                 累加和1     符合范围 √

0-1[1,-1]                累加和0     符合范围 √

0-2[1,-1,-2]         累加和-2    不符合范围 ×

0-3[1,-1,-2,3]    累加和1     符合范围  √

1-1范围的子数组

1-2范围的子数组

1-3范围的子数组

....

3-3范围的子数组               

 1     public static int countRangeSum2(int[] arr, int lower, int upper) {
 2         //空数组或者数组中没有元素返回0
 3         if (arr == null || arr.length == 0) {
 4             return 0;
 5         }
 6         
 7         // 暴力美
 8         int res = 0;
 9         for (int i = 0; i < arr.length; i++) {        // 观察数组中以i结尾的每个位置
10             for (int j = 0; j <= i; j++) {         // 从0位置开始到i位置 
11                 int sum = 0;
12                 for (int k = j; k <= i; k++) {     // 随着j的变化,收集arr[j]到arr[i]的每个数
13                     sum += arr[k];
14                 }
15                 if (sum >= lower && sum <= upper) {// 落在给定区间上,计数器++;
16                     res++;
17                 }    
18             }
19         }
20         return res;
21     }

 

 

 这个时间复杂度O(N3)

使用前缀和可以优化到O(N2)

使用前缀和 + 归并O(N * logN)

 

思想解放一下:

     0   1    2   3

  arr[ 1, -1, -2,  3]                                       范围[ -1, 1 ]

preSum[1,  0,  -2, 1]

 第一步转化: 看子数组,必须以

   0结尾             1结尾                2结尾             3结尾

       0-0                  1-1                  2-2                   3-3

                                   0-1                  1-2                   2-3

                                                           0-2                  1-3

                                                                                  0-3

            a个                b个                   c个                  d个

第二步转化:

      0   1    2   3

  arr[ 1, -1, -2,  3]                                       范围[ -1, 1 ]

preSum[1,  0,  -2, 1]

比如:有多少以3结尾的子数组累加和落在[ -1, 1 ],

前缀和有:

  一个数也没有时:0

   0 - 0位置的前缀和:1

   0 - 1位置的前缀和:0

   0 - 2位置的前缀和:-2

知道0-3累加和1,也就是问前缀和有多少落在[ -2, 0 ]上

 

假设0 - i整体累加和是X,题目目标[ Lower, up ],求必须以i位置结尾的子数组,有多少个在[ Lower, up ]上

等同于

去求i之前的所有前缀和中,有多少个前缀和在[ X-up, X-lower ]上。

         arr[ .... ]

---->sum[ ....x ]     也就是求x前,有多少数落在[ x-up, x-lower ] 上

 1 public static int merge(long[] arr, int L, int M, int R, int lower, int upper) {
 2         // 不merge但是,对于右组中的每个数X,求左组中有多少个数,位于[X-upper, X-Lower]
 3         int ans = 0;
 4         int windowL = L;
 5         int windowR = L;
 6         // 目前囊括进来的数
 7         // [windowL, windowR)
 8         for (int i = M + 1; i <= R; i++) {
 9             long min = arr[i] - upper;
10             long max = arr[i] - lower;
11             while (windowR <= M && arr[windowR] <= max) {
12                 windowR++;
13             }
14             while (windowL <= M && arr[windowL] < min) {
15                 windowL++;
16             }
17             ans += windowR - windowL;
18         }
19 
20         // 正常merge
21         long[] help = new long[R - L + 1];
22         int i = 0;
23         int p1 = L;
24         int p2 = M + 1;
25         while (p1 <= M && p2 <= R) {
26             help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
27         }
28         while (p1 <= M) {
29             help[i++] = arr[p1++];
30         }
31         while (p2 <= R) {
32             help[i++] = arr[p2++];
33         }
34         for (i = 0; i < help.length; i++) {
35             arr[L + i] = help[i];
36         }
37         return ans;
38     }

 

 

          

 

posted @ 2022-05-21 10:21  yzmarcus  阅读(27)  评论(0编辑  收藏  举报