原题地址:https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/submissions/
题目描述:
给定一个整数数组 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 个更小的元素.
解题方案:
题目给出相关话题为树状数组,线段树,二叉搜索树以及分治算法。实际上实现的代码中,需要自己去设计二叉搜索树。参考地址:https://blog.youkuaiyun.com/xuxuxuqian1/article/details/81544783
首先是定义节点的数据结构,val表示节点的数值,small表示节点的性质值,self记录的是与自己相同值的数值。
其次是定义搜索树的添加元素函数以及获取节点性质值函数。两个函数的设计都是递归的方法。
从根节点开始:
1.如果节点值大于目标值,那么递归到节点的左节点进行计数
2.如果节点值等于目标值,返回该节点处less的值
3.节点值小于目标值,返回节点自身数量+less+递归右节点(因为大于节点值也有可能小于目标值)
代码:
class Solution {
public:
struct node{
int small;
int val;
int self = 1;
node * left = NULL;
node * right = NULL;
node(int val, int small): small(small), val(val){};
};
node* add(node* root, int val)
{
if(root == NULL)
return new node(val,0);
if(val == root->val)
root->self += 1;
else if(val > root->val)
root->right = add(root->right, val);
else {
root->left = add(root->left,val);
root->small += 1;
}
return root;
}
int getnum(node* root, int val)
{
if(root == NULL)
return 0;
if(root->val == val)
return root->small;
if(root->val<val)
return root->small + root->self + getnum(root->right, val);
if(root->val>val)
return getnum(root->left, val);
return 0;
}
vector<int> countSmaller(vector<int>& nums) {
int n = nums.size();
if(n == 0)
return {};
if(n == 1)
return {0};
vector<int> count(n, 0);
node* root = new node(nums[n - 1], 0);
for(int i = n - 2; i >= 0; i --)
{
root = add(root, nums[i]);
count[i] = getnum(root, nums[i]);
}
return count;
}
};