维护x的秩

维护x的秩

题目描述

现在我们要读入一串数,同时要求在读入每个数的时候算出它的秩,即在当前数组中小于等于它的数的个数(不包括它自身),请设计一个高效的数据结构和算法来实现这个功能。

给定一个int数组A,同时给定它的大小n,请返回一个int数组,元素为每次加入的数的秩。保证数组大小小于等于5000。

测试样例:

[1,2,3,4,5,6,7],7
返回:[0,1,2,3,4,5,6]

思路:

链接:https://www.nowcoder.com/questionTerminal/0ade0d95c85349beb934a90b1d9b02be?f=discussion
来源:牛客网

用一个二叉查找树来维护当前已经插入的数组,小于等于该节点插入左子树内,
大于插入右子树内,递归调用。
这样,每次查询小于等于某个节点的节点数,分三种情况讨论,递归调用:
1.当前节点的值等于插入的节点的值,那么返回该节点的左子树数目就等于秩
2.当前节点的值大于插入的节点的值,那么递归调用左子树(因为该节点的本身
及其右子树都对秩没影响)
3.当前节点的值小于插入的节点的值,那么当前节点的所有左子树加上本身都是
该插入节点的秩,
然后加上插入的节点在右子树中的秩之和为改插入节点的秩
注意:1.只用记录当前节点的左子树的个数,2.每次都是先插再找出秩,所以每
次查找不会出现不在树中的情况。

代码如下:

package com.jiading.niuke;

/**
 * @program: Algorithm
 * @description: 维护x的秩
 * 现在我们要读入一串数,同时要求在读入每个数的时候算出它的秩,即在当前数组中小于等于它的数的个数(不包括它自身),请设计一个高效的数据结构和算法来实现这个功能。
 * 给定一个int数组A,同时给定它的大小n,请返回一个int数组,元素为每次加入的数的秩。保证数组大小小于等于5000。
 * @author: JiaDing
 * @create: 2020-07-31 23:08
 **/
public class Rank {
    public static int[] getRankOfNumber(int[] A, int n) {
        int[] ans = new int[n];
        Node node = null;
        for (int i = 0; i < n; i++) {
            if (node == null) {
                node = new Node(A[i]);
                ans[i] = 0;
            } else {
                ans[i] = node.insert(A[i]);
            }
        }
        return ans;
    }

    static class Node {
        int leftSize = 0;
        int val = 0;
        Node left = null, right = null;

        public Node(int val) {
            this.val = val;
        }

        public int insert(int val) {
            if (this.val <= val) {
                if (this.right != null) {
                    return leftSize + 1 + this.right.insert(val);
                } else {
                    this.right = new Node(val);
                    return this.leftSize + 1;
                }
            } else {
                this.leftSize++;
                if (this.left != null) {

                    return this.left.insert(val);
                } else {

                    this.left = new Node(val);
                    return 0;
                }
            }
        }
    }

    public static void main(String[] args) {
        int[] rankOfNumber = getRankOfNumber(new int[]{5, 1, 7, 9, 3, 4, 2}, 7);
        for (int i : rankOfNumber
        ) {
            System.out.println(i);
        }
    }
}

有一点要注意,就是我们保留一个leftSize字段就可以了,没必要用rightSize字段,因为不可能用到这个值(leftSize只有比left都大的时候才用,但是没有很方便的方法测量是否比right的都大,所以没用)

在插入的时候其实就能把秩算出来了,没必要单独再计算一次

posted @ 2020-07-31 23:41  别再闹了  阅读(76)  评论(0)    收藏  举报