​LeetCode刷题实战315:计算右侧小于当前元素的个数

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 计算右侧小于当前元素的个数,我们先来看题面:

https://leetcode-cn.com/problems/count-of-smaller-numbers-after-self/

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 个更小的元素

解题

https://blog.youkuaiyun.com/qq_41855420/article/details/88368675

方法一:蛮力法。时间复杂度O(n2),额外的空间复杂度O(n)

class Solution {
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)

class Solution {
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)
二叉搜索树的特性:中序遍历序列严格递增。

class Solution {
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;
    }
};

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:

LeetCode1-300题汇总,希望对你有点帮助!

LeetCode刷题实战301:删除无效的括号

LeetCode刷题实战302:包含全部黑色像素的最小矩阵

LeetCode刷题实战303:区域和检索 - 数组不可变

LeetCode刷题实战304:二维区域和检索 - 矩阵不可变

LeetCode刷题实战305:岛屿数量II

LeetCode刷题实战306:累加数

LeetCode刷题实战307:区域和检索 - 数组可修改

LeetCode刷题实战308:二维区域和检索 - 可变

LeetCode刷题实战309:最佳买卖股票时机含冷冻期

LeetCode刷题实战310:最小高度树

LeetCode刷题实战311:稀疏矩阵的乘法

LeetCode刷题实战312:戳气球

LeetCode刷题实战313:超级丑数

LeetCode刷题实战314:二叉树的竖直遍历

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值