LeetCode 第一道困难题--计算右侧小于当前元素的个数

本文分享了一次刷题经历,探讨了如何优化算法效率,从冒泡排序到利用二叉搜索树解决计数右侧较小元素的问题,展示了代码实现过程。

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

不刷题,永远不知道自己是多么菜,一刷题才发现自己学的是假计算机专业,希望自己能够坚持下去,在接下来的日子继续刷题,完整的看完《算法导论》。

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

 

这道题其实,一看就发现不就是冒泡排序吗,两次循环就搞定了,啥也不说上代码:


vector<int> CAlgCountSmaller::countSmaller(vector<int>& nums) 
{

	vector<int> vecRetSmall;
	int iArraySize = nums.size();
	if (iArraySize < 1)
	{
		return vecRetSmall;
	}

	//!初始化vector数组
	vecRetSmall.assign(iArraySize, 0);
	for (size_t i = 0; i < iArraySize; i++)
	{
		for (int iSecond = i + 1; iSecond < iArraySize; iSecond++)
		{
			if (nums[iSecond] < nums[i])
			{
				vecRetSmall[i]++;
			}
		}
	}

	return vecRetSmall;
}

范例一下就测试通过了,感觉就这还困难级别吗?冒着忐忑的心态提交,果然超出时间限制,16个用例,通过了15个。

在平时写代码过程中,两次循环用的太多了,从来没考虑过效率问题。现在是时候要考虑了!

1.有没有重复的比较出现

答案是绝对有的.....

数组用 A={a1,a2....ai,....a(size)}; 0 < i < size; 

假设第一次遍历后,有第a1 大于区间[a3,a100]所有的数,a1小于a2

那么,第二次遍历a2时,还需要再次遍历a3-a100之间的值吗?

当然不需要了,那么怎么才能避免这种冲突了,第一想法当然是记录下来已经比较的结果了,再次比较的时候,先于已经比较的进行判断,那么如何记录已经知道的结果呢?这不就是维护一个二叉搜素树吗?

好了,看代码吧,

class Solution {
public:


struct ST_TreeNode
{
	//!节点值
	int iValue; 
	//!左子树个数
	int iCount;	 

	//左子树
	ST_TreeNode* m_pLeftNode;
	//!右子树
	ST_TreeNode* m_pRgintNode;
};

class ST_Tree
{
public:
	ST_Tree(int iValue) :stRootNode{0,0,NULL,NULL} { stRootNode.iValue = iValue; }

	void InsertNode(int iValue, int& iSmallCount)
	{
		pri_insert(&stRootNode, iValue, iSmallCount);
	}

	void pri_insert(ST_TreeNode* pNode, int iInsertValue, int& iSmallCount)
	{
		if (!pNode)
		{
			return;
		}

		//!新插入节点值大于当前节点值
		if (iInsertValue > pNode->iValue)
		{
			iSmallCount += pNode->iCount + 1;
			//!右节点为空,则创建新的节点
			if (NULL == pNode->m_pRgintNode)
			{
				pNode->m_pRgintNode = new ST_TreeNode{ iInsertValue ,0, NULL, NULL };
			}
			//右节点不为空,则递归在右节点插入
			else
			{
				pri_insert(pNode->m_pRgintNode, iInsertValue, iSmallCount);
			}
		}
		//!新插入节点值小等于当前节点值
		else
		{
			pNode->iCount++;
			//!左节点为空,则创建新的节点
			if (NULL == pNode->m_pLeftNode)
			{
				pNode->m_pLeftNode = new ST_TreeNode{ iInsertValue ,0, NULL, NULL };
			}
			//左节点不为空,则递归在左节点插入
			else
			{
				pri_insert(pNode->m_pLeftNode, iInsertValue, iSmallCount);
			}
		}
	}

	//!树节点
	ST_TreeNode stRootNode;
};

    vector<int> countSmaller(vector<int>& nums) {
	vector<int> vecSmall;
	int iArraySize = nums.size();
	if (iArraySize < 1)
	{
		return vecSmall;
	}
	ST_Tree stBSTree(nums[iArraySize -1]);
	vecSmall.assign(nums.size(), 0);
	for (int i = iArraySize - 2; i >= 0; --i) {
		stBSTree.InsertNode(nums[i], vecSmall[i]);
	}

	return vecSmall;
    }
};

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值