LeetCode315

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;
    }
   
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值