LeetCode刷题记161
315. 计算右侧小于当前元素的个数
class Solution {
public List<Integer> countSmaller(int[] nums) {
// discretize离散化数字
Set<Integer> set = new HashSet<Integer>();
for (int num : nums) {
set.add(num);
}
int[] tmp = new int[set.size()];
int id = 0;
for (int num : set) {
tmp[id ++] = num;
}
Arrays.sort(tmp);
// TreeMap<Integer, Integer> map = new TreeMap<Integer, Integer>();
// id = 0;
// for (int num : set) {
// map.put(num, id ++);
// }
int[] tree_array = new int[nums.length + 5]; // 记录树状数组
List<Integer> ans = new ArrayList<Integer>();
for (int i = nums.length - 1; i >= 0; --i) {
// int pos = map.get(nums[i]);
int pos = Arrays.binarySearch(tmp, nums[i]);
ans.add(query(pos, tree_array));
update(pos + 1, 1, tree_array);
}
Collections.reverse(ans);
return ans;
}
private int lowBit(int x) {
return x & (-x);
}
private void update(int pos, int num, int[] c) {
while (pos < c.length) {
c[pos] += num;
pos += lowBit(pos);
}
}
private int query(int pos, int[] c) {
int ret = 0;
while (pos > 0) {
ret += c[pos];
pos -= lowBit(pos);
}
return ret;
}
}
经典的树状数组的题目,但是我忘记树状数组怎么写的了,还是看了答案。。。
树状数组原理不讲了,网上很多,而且我讲不清楚。主要说一下怎么记忆update和query函数,哈哈哈。
update函数是更新数组的,那么对应位置就要加num;
update是up,位置更新对应“+”,那么循环就要小于上限->数组长度。
private void update(int pos, int num, int[] c) {
while (pos < c.length) {
c[pos] += num;
pos += lowBit(pos);
}
}
query是查询,那么返回结果的数据要加上对应位置的数字;
位置更新是要加上当前位置之前的数字,所以是“-”,那么循环就要大于下限->0。
private int query(int pos, int[] c) {
int ret = 0;
while (pos > 0) {
ret += c[pos];
pos -= lowBit(pos);
}
return ret;
}
小知识点:
public static int binarySearch(Object[] a, Object key)
通过二分法在已经排好序的数组中查找指定的元素,并返回该元素的下标;
如果数组中不存在该元素,则会返回 -(插入点 + 1)。
int[] a = {10, 20, 30, 40};
System.out.println(Arrays.binarySearch(a, 20)); //1
System.out.println(Arrays.binarySearch(a, 25)); //-3,插入点在20和30之间,就是2的位置
System.out.println(Arrays.binarySearch(a, 35)); //-4
用归并排序的方法再做一遍