Leetcode 315.计算右侧小于当前元素的个数(Count of Smaller Numbers After Self)

本文详细解析了LeetCode第315题“计算右侧小于当前元素的个数”的两种解法:二叉搜索树和树状数组。通过构建二叉搜索树并记录左子树节点数,或使用树状数组进行前缀和查询,实现了高效求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Leetcode 315.计算右侧小于当前元素的个数

1 题目描述(Leetcode题目链接

  给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。

输入: [5,2,6,1]
输出: [2,1,1,0] 
解释:
5 的右侧有 2 个更小的元素 (21).
2 的右侧仅有 1 个更小的元素 (1).
6 的右侧有 1 个更小的元素 (1).
1 的右侧有 0 个更小的元素.

2 题解

  利用二叉搜索树的性质,节点左子树的值都小于节点值,右子树的值都大于节点值,所以我们从数组右边遍历数组,构建二叉搜索树,每个节点使用一个值来记录左子树的节点数量。详见代码注释。

class BST:
    def __init__(self, value):
        self.val = value
        self.lcount = 0		# 记录左子树的节点数量
        self.parent = None	# 父节点指针
        self.left = None
        self.right = None


class Solution:
    def insert(self, root, value):
        n = 0		# n数组右边小于value的值的数量
        y = None
        while root:
            y = root
            if value <= root.val:
            	# 如果要插入的值小于等于当前节点,则当前节点的左子树数量加1
                root.lcount += 1		
                root = root.left
            else:
            	# 如果要插入的值大于当前节点,则当前节点以及当前节点的左子树节点数量都是小于value的
                n += root.lcount + 1	
                root = root.right
        z = BST(value)
        z.parent = y
        if value <= y.val:
            y.left = z
        else:
            y.right = z
        return n

            
    def countSmaller(self, nums: List[int]) -> List[int]:
        if not nums:
            return []
        res = [0]
        self.root = BST(nums[-1])
        for i in range(len(nums) - 2, -1, -1):
            n = self.insert(self.root, nums[i])
            res.append(n)
        return res[::-1]
        

  树状数组解法

class Solution:

    def countSmaller(self, nums: List[int]) -> List[int]:

        def lowbit(x):
            return x & -x

        def getSum(n):
            s = 0
            i = n
            while i > 0:
                s += C[i]
                i -= lowbit(i)
            return s
        
        def update(n):
            i = n
            while i < 20010:
                C[i] += 1
                i += lowbit(i)

        res = []
        C = [0 for i in range(20010)]
        for i in nums[::-1]:
            update(i+10001)
            res.append(getSum(i+10000))

        return res[::-1]
class Solution {

public:
    int lowbit(int x){
        return x & -x;
    }
    int getSum(int n, vector<int>& C){
        int s = 0;
        for (int i = n; i > 0; i -= lowbit(i))
            s += C[i];
        return s;
    }

    void update(int x, vector<int>& C){
        for (int i = x; i < C.size(); i += lowbit(i))
            C[i] += 1;
    }

    vector<int> countSmaller(vector<int>& nums) {
        reverse(nums.begin(), nums.end());
        int n = nums.size();
        vector<int>C(20010);
        vector<int>res(n);
        for (int i = 0; i < nums.size(); i++){
            update(nums[i]+10001, C);
            res[i] = getSum(nums[i]+10000, C);
        }
        reverse(res.begin(), res.end());
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值