int query(int left, int right, int threshold),查询数组中下标从left到right区间中,left <= i <= right,arr[i]相同的个数 >= threshold的值,threshold * 2 > right - left + 1,不存在则返回 -1. 例如:arr=[1,1,2,2,1,1],则 query(0, 5, 4) = 1.
publicintquery(int left, int right, int threshold) { return wtree.query(left, right, threshold); }
privateclassWaveletTree { /** * original array */ privateint[] S; /** * distinct ordered elements in {@link S} */ privateint[] orderedAlphabet; private Node root; /** * the same value in {@link S} map to its indices (ordered) */ private Map<Integer, List<Integer>> v2indices;
publicWaveletTree(int[] arr) { this.S = arr; List<Integer> indices = newArrayList<>(arr.length); TreeSet<Integer> set = newTreeSet<>(); for (inti=0; i < arr.length; i++) { indices.add(i); set.add(arr[i]); } this.orderedAlphabet = set.stream().mapToInt(Integer::intValue).toArray(); this.v2indices = newHashMap<>(); this.root = build(indices, 0, this.orderedAlphabet.length - 1); }
/** * build a WT (wavelet tree) * * @param indices indices of {@link S} * @param lo start index of {@link orderedAlphabet} (include) * @param hi end index of {@link orderedAlphabet} (include) * @return root of WT */ private Node build(List<Integer> indices, int lo, int hi) { if (indices.size() == 0) { returnnull; } if (lo == hi) { Nodenode=newNode(lo, hi); this.v2indices.put(this.orderedAlphabet[lo], indices); return node; } Nodenode=newNode(lo, hi); intmid= lo + (hi - lo) / 2; List<Integer> left = newArrayList<>(), right = newArrayList<>(); for (int i : indices) { if (S[i] <= orderedAlphabet[mid]) { left.add(i); } else { right.add(i); } node.freq.add(right.size()); } node.lc = build(left, lo, mid); node.rc = build(right, mid + 1, hi); return node; }
/** * query the kth smallest element in {@link S} from i to j * * @param root root of WT * @param i start index (include) * @param j end index (include) * @param k the kth smallest * @return the node of that element */ private Node quantile(Node root, int i, int j, int k) { if (root.lo == root.hi) { return root; } if (k <= countMapToLeft(root, i, j)) { return quantile(root.lc, mapLeft(root, i), mapLeft(root, j), k); } else { return quantile(root.rc, 0, mapRight(root, j), k - root.getFreq(j)); } }
/** * the number of {@link S} from i to j that mapped to left child * * @param root root of WT * @param i start index (include) * @param j end index (include) * @return number >= 0 */ privateintcountMapToLeft(Node root, int i, int j) { return j + 1 - root.getFreq(j) - (i - root.getFreq(i - 1)); }
/** * the index of left child WT that mapped from index i * * @param root root of WT * @param i current index i * @return left child WT index */ privateintmapLeft(Node root, int i) { return Math.max(i - root.getFreq(i), 0); }
/** * the index of right child WT that mapped from index i * * @param root root of WT * @param i current index i * @return right child WT index */ privateintmapRight(Node root, int i) { return Math.max(root.getFreq(i) - 1, 0); }
publicintquery(int left, int right, int threshold) { Nodenode= quantile(root, left, right, threshold); List<Integer> indices = v2indices.get(this.orderedAlphabet[node.lo]); if (indices.size() >= threshold) { intlow= Collections.binarySearch(indices, left); if (low < 0) { low = ~low; } inthi= Collections.binarySearch(indices, right); if (hi < 0) { hi = ~hi - 1; } if (hi - low + 1 >= threshold) { return orderedAlphabet[node.lo]; } } return -1; }
privateclassNode { /** * lo start index of {@link orderedAlphabet} (include) * hi end index of {@link orderedAlphabet} (include), e.g. orderedAlphabet[lo,...,hi] */ publicint lo, hi; /** * the number of elements that mapped to right child WT each from {@link lo} to {@link hi} */ public List<Integer> freq; public Node lc, rc;