publicQueryBox2(int[] arr){ map = new HashMap<>(); for (int i = 0; i < arr.length; i++) { if (!map.containsKey(arr[i])) { map.put(arr[i], new ArrayList<>()); } map.get(arr[i]).add(i); } }
publicintquery(int L, int R, int value){ if (!map.containsKey(value)) return0; ArrayList<Integer> indexArr = map.get(value); // 查询<L的下标有几个 int a = countLess(indexArr, L); // 查询<R+1的下标有几个 int b = countLess(indexArr, R + 1); return b - a; }
// 在有序数组中,用二分法数出<limit 的数有几个 // 也就是用二分法,找到<limit的数中最右的位置 privateintcountLess(ArrayList<Integer> arr, int limit){ int L = 0; int R = arr.size() - 1; int mostRight = -1; while (L <= R) { int mid = L + ((R - L) >> 1); if (arr.get(mid) < limit) { mostRight = mid; L = mid + 1; } else { R = mid - 1; } } return mostRight + 1; } }
$O(mlogn)$
扩展:
如果是求范围内累加和
可以生成一个前缀和数组类似本题
腾讯原题
给定整数 power。给定一个数组 arr。给定一个数组 reverse。含义如下
arr 的长度一定是 2 的 power 次方,reverse1 每个值一定都在 0 ~ power范围。
// originArr长度一定是2的power次方 // reverseArr中每一个值,都是0-power范围上的数 publicstaticint[] reversePair1(int[] originArr, int[] reverseArr, int power) { int[] ans = newint[reverseArr.length]; for (int i = 0; i < reverseArr.length; i++) { // 1 << (reverseArr[i]) == r[i]的2次方 reverseArray(originArr, 1 << (reverseArr[i])); ans[i] = countReversePair(originArr); } return ans; }
publicstaticvoidreverseArray(int[] originArr, int teamSize){ if (teamSize < 2) return; for (int i = 0; i < originArr.length; i += teamSize) { reversePart(originArr, i, i + teamSize - 1); } }
publicstaticvoidreversePart(int[] arr, int L, int R){ while (L < R) { int temp = arr[L]; arr[L++] = arr[R]; arr[R--] = temp; } }
publicstaticintcountReversePair(int[] originArr){ int ans = 0; for (int i = 0; i < originArr.length; i++) { for (int j = i + 1; j < originArr.length; j++) { if (originArr[i] > originArr[j]) { ans++; } } } return ans; }
// recordDown[i] 2的i次方个数一组的划分中,降序的数量 // recordUp[i] 2的i次方个数一组的划分中,升序的数量 int[] ans = newint[reverseArr.length]; for (int i = 0; i < reverseArr.length; i++) { int curPower = reverseArr[i]; // =3 2的1次方、2次方、3次方 要调整 for (int p = 1; p <= curPower; p++) { int tmp = recordDown[p]; recordDown[p] = recordUp[p]; recordUp[p] = tmp; } for (int p = 1; p <= power; p++) { ans[i] += recordDown[p]; } } return ans; }
publicstaticvoidprocess(int[] originArr, int L, int R, int power, int[] record){ if (L == R) { return; } int mid = L + ((R - L) >> 1); process(originArr, L, mid, power - 1, record); process(originArr, mid + 1, R, power - 1, record); record[power] += merge(originArr, L, mid, R); }
publicstaticintmerge(int[] arr, int L, int m, int r){ int[] help = newint[r - L + 1]; int i = 0; int p1 = L; int p2 = m + 1; int ans = 0; while (p1 <= m && p2 <= r) { ans += arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; } while (p1 <= m) { help[i++] = arr[p1++]; } while (p2 <= r) { help[i++] = arr[p2++]; } for (i = 0; i < help.length; i++) { arr[L + i] = help[i]; } return ans; }