Leetcode 315.计算右侧小于当前元素的个数
1 题目描述(Leetcode题目链接)
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质: counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
输入: [5,2,6,1]
输出: [2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1).
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;
}
};