You are given an integer array nums and you have to return a new counts array. The counts array has the property where counts[i]
is the number of smaller elements to the right of nums[i]
.
Example:
Given nums = [5, 2, 6, 1] To the right of 5 there are 2 smaller elements (2 and 1). To the right of 2 there is only 1 smaller element (1). To the right of 6 there is 1 smaller element (1). To the right of 1 there is 0 smaller element.
Return the array [2, 1, 1, 0]
.
这道题如果使用O(N^2)的穷搜方法是绝对超时的。·但是从最右边元素开始处理的想法却是正确的。
使用什么方法的可以减少查询次数呢?最妙的做法是我在LeetCode 的solution里看到的,这个方法在处理每个元素的同时维护了一棵二叉查找树,这样我们每次处理一个新的元素时,只需要从根节点处对其进行插入,并且记录每次走右子树时的sum值(因为右子树值均大于左子树),而每个右子树节点都记录了其左子树的节点数(包括重复的值)。
因此,先定义节点类
class Node {
public Node(int dup,int val){
this.dup = dup; //记录重复次数
this.val = val;
this.left = null;
this.right = null;
}
public void incDup(){
this.dup++;
}
public int getDup(){
return this.dup;
}
private int dup;
public int sum; //记录该节点左子树中节点总数
public int val;
public Node left;
public Node right;
}
再实现一个二叉查找树插入函数,具有更新节点内部值的功能。
public Node insert(List<Integer> counts,Node node,int curvalue,int sum){
if (node == null) {
node = new Node(1,curvalue);
counts.add(0,sum);
}
else if (node.val == curvalue) {
node.incDup();
counts.add(0,sum+node.sum);
}
else if (node.val > curvalue) {
node.sum++;
node.left = insert(counts,node.left,curvalue,sum);
}
else node.right = insert(counts,node.right,curvalue,sum+node.getDup()+node.sum);
return node;
}
注意node == null时的情况,实际上是长出一个新的节点。而insert 函数返回的一直是根节点。
完整的solution:
class Node {
public Node(int dup,int val){
this.dup = dup;
this.val = val;
this.left = null;
this.right = null;
}
public void incDup(){
this.dup++;
}
public int getDup(){
return this.dup;
}
private int dup;
public int sum;
public int val;
public Node left;
public Node right;
}
public class Solution {
public List<Integer> countSmaller(int[] nums) {
List<Integer> counts = new ArrayList<Integer>();
Node root = null;
for (int i = nums.length-1;i>=0;i--){
root = insert(counts,root,nums[i],0);
}
return counts;
}
public Node insert(List<Integer> counts,Node node,int curvalue,int sum){
if (node == null) {
node = new Node(1,curvalue);
counts.add(0,sum);
}
else if (node.val == curvalue) {
node.incDup();
counts.add(0,sum+node.sum);
}
else if (node.val > curvalue) {
node.sum++;
node.left = insert(counts,node.left,curvalue,sum);
}
else node.right = insert(counts,node.right,curvalue,sum+node.getDup()+node.sum);
return node;
}
}