Give you an integer array (index from 0 to n-1, where n is the size of this array, value from 0 to 10000) and an query list. For each query, give you an integer, return the number of element in the array that are smaller than the given integer.
Example
Example 1:
Input: array =[1,2,7,8,5] queries =[1,8,5]
Output:[0,4,2]
Example 2:
Input: array =[3,4,5,8] queries =[2,4]
Output:[0,1]
Challenge
Could you use three ways to do it.
- Just loop
- Sort and binary search
- Build Segment Tree and Search.
Notice
public class Solution {
/**
* @param A: An integer array
* @param queries: The query list
* @return: The number of element in the array that are smaller that the given integer
*/
public List<Integer> countOfSmallerNumber(int[] A, int[] queries) {
// write your code here
List<Integer> ans = new ArrayList<>();
if (queries == null || queries.length == 0) {
return ans;
}
// step 1: build a segment tree
SegmentTree segmentTree = new SegmentTree(A);
// step 2; query the segment tree
for (int query : queries) {
int count = segmentTree.query(0, query - 1);
ans.add(count);
}
return ans;
}
}
class SegmentTree {
private SegmentTreeNode root = null;
public SegmentTree(int[] A) {
if (A == null || A.length == 0) {
return;
}
Map<Integer, Integer> numToCount = new HashMap<>();
for (int num : A) {
int count = numToCount.getOrDefault(num, 0);
count += 1;
numToCount.put(num, count);
}
root = buildSegmentTree(0, 10000, numToCount);
}
public int query(int start, int end) {
return queryHelper(root, start, end);
}
private int queryHelper(SegmentTreeNode root, int start, int end) {
if (root == null || start > end) {
return 0;
}
if (start == root.start && end == root.end) {
return root.count;
}
int mid = root.start + (root.end - root.start) / 2;
int leftCount = queryHelper(root.left, Math.max(start, root.start), Math.min(end, mid));
int rightCount = queryHelper(root.right, Math.max(mid + 1, start), Math.min(root.end, end));
return leftCount + rightCount;
}
private SegmentTreeNode buildSegmentTree(int start, int end, Map<Integer, Integer> numToCountMap) {
if (start > end) {
return null;
}
if (start == end) {
int count = numToCountMap.getOrDefault(start, 0);
return new SegmentTreeNode(start, end, count);
}
int mid = start + (end - start) / 2;
SegmentTreeNode leftChild = buildSegmentTree(start, mid, numToCountMap);
SegmentTreeNode rightChild = buildSegmentTree(mid + 1, end, numToCountMap);
SegmentTreeNode root = new SegmentTreeNode(start, end, leftChild.count + rightChild.count);
root.left = leftChild;
root.right = rightChild;
return root;
}
}
class SegmentTreeNode {
int start, end;
int count;
SegmentTreeNode left, right;
public SegmentTreeNode(int start, int end, int count) {
this.start = start;
this.end = end;
this.count = count;
left = right = null;
}
}
Another solution from Jiuzhang:Build an empty segment tree first, with all count zero. Then update the tree with the new value.
/**
* 本参考程序来自九章算法,由 @九章算法 提供。版权所有,转发请注明出处。
* - 九章算法致力于帮助更多中国人找到好的工作,教师团队均来自硅谷和国内的一线大公司在职工程师。
* - 现有的面试培训课程包括:九章算法班,系统设计班,算法强化班,Java入门与基础算法班,Android 项目实战班,
* - Big Data 项目实战班,算法面试高频题班, 动态规划专题班
* - 更多详情请见官方网站:http://www.jiuzhang.com/?source=code
*/
public class Solution {
/**
* @param A: An integer array
* @return: The number of element in the array that
* are smaller that the given integer
*/
class SegmentTreeNode {
public int start, end;
public int count;
public SegmentTreeNode left, right;
public SegmentTreeNode(int start, int end, int count) {
this.start = start;
this.end = end;
this.count = count;
this.left = this.right = null;
}
}
SegmentTreeNode root;
public SegmentTreeNode build(int start, int end) {
// write your code here
if(start > end) { // check core case
return null;
}
SegmentTreeNode root = new SegmentTreeNode(start, end, 0);
if(start != end) {
int mid = (start + end) / 2;
root.left = build(start, mid);
root.right = build(mid+1, end);
} else {
root.count = 0;
}
return root;
}
public int querySegmentTree(SegmentTreeNode root, int start, int end) {
// write your code here
if(start == root.start && root.end == end) { // 相等
return root.count;
}
int mid = (root.start + root.end)/2;
int leftcount = 0, rightcount = 0;
// 左子区
if(start <= mid) {
if( mid < end) { // 分裂
leftcount = querySegmentTree(root.left, start, mid);
} else { // 包含
leftcount = querySegmentTree(root.left, start, end);
}
}
// 右子区
if(mid < end) { // 分裂 3
if(start <= mid) {
rightcount = querySegmentTree(root.right, mid+1, end);
} else { // 包含
rightcount = querySegmentTree(root.right, start, end);
}
}
// else 就是不相交
return leftcount + rightcount;
}
public void modifySegmentTree(SegmentTreeNode root, int index, int value) {
// write your code here
if(root.start == index && root.end == index) { // 查找到
root.count += value;
return;
}
// 查询
int mid = (root.start + root.end) / 2;
if(root.start <= index && index <=mid) {
modifySegmentTree(root.left, index, value);
}
if(mid < index && index <= root.end) {
modifySegmentTree(root.right, index, value);
}
//更新
root.count = root.left.count + root.right.count;
}
public ArrayList<Integer> countOfSmallerNumber(int[] A, int[] queries) {
// write your code here
root = build(0, 10000);
ArrayList<Integer> ans = new ArrayList<Integer>();
int res;
for(int i = 0; i < A.length; i++) {
modifySegmentTree(root, A[i], 1);
}
for(int i = 0; i < queries.length; i++) {
res = 0;
if(queries[i] > 0)
res = querySegmentTree(root, 0, queries[i] - 1);
ans.add(res);
}
return ans;
}
}
No comments:
Post a Comment