题目
题干
该问题计算右侧小于当前元素的个数 题面:
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].
给定一个整数数组 nums,按要求返回一个新数组 counts。数组 counts 有该性质:counts[i] 的值是 nums[i] 右侧小于 nums[i] 的元素的数量。
示例
输入:nums = [5,2,6,1]
输出:[2,1,1,0]
解释:
5 的右侧有 2 个更小的元素 (2 和 1)
2 的右侧仅有 1 个更小的元素 (1)
6 的右侧有 1 个更小的元素 (1)
1 的右侧有 0 个更小的元素
题解
方法一:蛮力法。
时间复杂度O(n2),额外的空间复杂度O(n)
Python
class Solution1:
def __init__(self, nums) -> None:
self.nums = nums
def countSmaller(self):
nums_size = len(self.nums)
result = [0] * nums_size
for i in range(nums_size):
for j in range(i+1, nums_size):
if self.nums[i] > self.nums[j]:
result[i] = result[i] + 1
return result
C++
using namespace std;
#include <iostream>
#include <vector>
class Solution1 {
public:
vector<int> countSmaller(vector<int>& nums) {
int numsSize = nums.size();
vector<int> result(numsSize, 0);//用于储存nums[i]右边比它小的个数
for (int i = 0; i < numsSize; ++i){
//寻找[i + 1, numsSize - 1]中小于nums[i]的元素个数
for (int j = i + 1; j < numsSize; ++j){
if (nums[i] > nums[j]){
result[i] += 1;
}
}
}
return result;
}
};
方法二:使用容器。
map(默认是按照key从小到大进行排序)进行标记。时间复杂度O(nlog2n),额外的空间复杂度O(n)
Python
class Solution2:
def __init__(self, nums) -> None:
self.nums = nums
def countSmaller(self):
nums_size = len(self.nums)
leftNumCntMap = {}
result = [0] * nums_size
for i in range(nums_size-1,-1,-1):
for k,v in sorted(leftNumCntMap.items()):
if k >= self.nums[i]:
break
result[i] += v
leftNumCntMap[self.nums[i]] = leftNumCntMap.setdefault(self.nums[i], 0) + 1
return result
C++
using namespace std;
#include <iostream>
#include <vector>
#include <map>
class Solution2 {
public:
vector<int> countSmaller(vector<int>& nums) {
int numsSize = nums.size();
map<int, int> leftNumCntMap;//用于标记nums[i]左边各个元素出现的次数
vector<int> result(numsSize, 0);//用于储存nums[i]右边比它小的个数
for (int i = numsSize - 1; i >= 0; --i){//从后往前进行扫描
//在map中寻找比nums[i]小的个数
for (auto &pair : leftNumCntMap){
if (pair.first >= nums[i]){
break;
}
result[i] += pair.second;
}
//将nums[i]标记出现次数增加
leftNumCntMap[nums[i]] += 1;
}
return result;
}
};
方法三: 构建二叉搜索树。
利用二叉搜索树的特性,计算比当前节点小的个数。时间复杂度O(nlog2n),额外的空间复杂度O(n) 。
二叉搜索树的特性:中序遍历序列严格递增。
C++
using namespace std;
#include <iostream>
#include <vector>
class Solution3 {
private:
struct BSTNode{
int val;
int leftCount;//标记当前节点左端的节点数(记不比val大的个数)
BSTNode *left;
BSTNode *right;
BSTNode(int x):val(x),left(nullptr),right(nullptr),leftCount(0){}
};
public:
//将insert_node插入node二叉搜索树中,并将node中节点值比insert_node小的个数放入count_small中
void BST_insert(BSTNode *treeRoot, BSTNode *insert_node, int &count_small){
if(insert_node->val <= treeRoot->val){//需要插入treeRoot的左端
treeRoot->leftCount += 1;//左端节点自增
if(treeRoot->left){
BST_insert(treeRoot->left, insert_node, count_small);
}else{
treeRoot->left=insert_node;
}
}
else{//插入treeRoot的右端
count_small += treeRoot->leftCount + 1;//最小值为当前节点右端节点个数 + 1(当前根节点)
if(treeRoot->right){
BST_insert(treeRoot->right, insert_node, count_small);
}else{
treeRoot->right=insert_node;
}
}
}
vector<int> countSmaller(vector<int>& nums) {
//创建二叉查找树节点池
vector<BSTNode*> node_vec;
for (auto num : nums){
node_vec.push_back(new BSTNode(num));
}
int node_vecSize = node_vec.size();
vector<int> result(node_vecSize, 0);
//将第n - 2到0第个节点插入到以第n - 1节点为根节点的二叉排序树中
//插入过程中计算每个节点的countSmaller
for(int i = node_vecSize - 2; i >= 0; --i){
BST_insert(node_vec[node_vecSize - 1], node_vec[i], result[i]);
}
return result;
}
};