闻缺陷则喜何志丹

闻缺陷则喜何志丹

本文涉及知识点

离散化 树状树状

LeetCode 100246 将元素分配到两个数组中

给你一个下标从 1 开始、长度为 n 的整数数组 nums 。
现定义函数 greaterCount ,使得 greaterCount(arr, val) 返回数组 arr 中 严格大于 val 的元素数量。
你需要使用 n 次操作,将 nums 的所有元素分配到两个数组 arr1 和 arr2 中。在第一次操作中,将 nums[1] 追加到 arr1 。在第二次操作中,将 nums[2] 追加到 arr2 。之后,在第 i 次操作中:

如果 greaterCount(arr1, nums[i]) > greaterCount(arr2, nums[i]) ,将 nums[i] 追加到 arr1 。
如果 greaterCount(arr1, nums[i]) < greaterCount(arr2, nums[i]) ,将 nums[i] 追加到 arr2 。
如果 greaterCount(arr1, nums[i]) == greaterCount(arr2, nums[i]) ,将 nums[i] 追加到元素数量较少的数组中。
如果仍然相等,那么将 nums[i] 追加到 arr1 。
连接数组 arr1 和 arr2 形成数组 result 。例如,如果 arr1 == [1,2,3] 且 arr2 == [4,5,6] ,那么 result = [1,2,3,4,5,6] 。
返回整数数组 result 。
示例 1:
输入:nums = [2,1,3,3]
输出:[2,3,1,3]
解释:在前两次操作后,arr1 = [2] ,arr2 = [1] 。
在第 3 次操作中,两个数组中大于 3 的元素数量都是零,并且长度相等,因此,将 nums[3] 追加到 arr1 。
在第 4 次操作中,两个数组中大于 3 的元素数量都是零,但 arr2 的长度较小,因此,将 nums[4] 追加到 arr2 。
在 4 次操作后,arr1 = [2,3] ,arr2 = [1,3] 。
因此,连接形成的数组 result 是 [2,3,1,3] 。
示例 2:
输入:nums = [5,14,3,1,2]
输出:[5,3,1,2,14]
解释:在前两次操作后,arr1 = [5] ,arr2 = [14] 。
在第 3 次操作中,两个数组中大于 3 的元素数量都是一,并且长度相等,因此,将 nums[3] 追加到 arr1 。
在第 4 次操作中,arr1 中大于 1 的元素数量大于 arr2 中的数量(2 > 1),因此,将 nums[4] 追加到 arr1 。
在第 5 次操作中,arr1 中大于 2 的元素数量大于 arr2 中的数量(2 > 1),因此,将 nums[5] 追加到 arr1 。
在 5 次操作后,arr1 = [5,3,1,2] ,arr2 = [14] 。
因此,连接形成的数组 result 是 [5,3,1,2,14] 。
示例 3:
输入:nums = [3,3,3,3]
输出:[3,3,3,3]
解释:在 4 次操作后,arr1 = [3,3] ,arr2 = [3,3] 。
因此,连接形成的数组 result 是 [3,3,3,3] 。
提示:
3 <= n <= 10
1 <= nums[i] <= 10

预备知识

本题的数据最大10,如果不离散化,空间复杂度会超。
离散化:不改变各数值相对大小的前提下,尽可能得减小各数值。
比如:{3,7,7,8} 变成{1,2,2,3}。
树状数组,可以在O(logn)时间更新数值和求和。

代码

template<class ELE = int >
class CTreeArr
{
public:
	CTreeArr(int iSize) :m_vData(iSize + 1)
	{

	}
	void Add(int index, ELE value)
	{
		index++;
		while (index < m_vData.size())
		{
			m_vData[index] += value;
			index += index & (-index);
		}
	}
	ELE Sum(int index)
	{
		index++;
		ELE ret = 0;
		while (index)
		{
			ret += m_vData[index];
			index -= index & (-index);
		}
		return ret;
	}
	ELE Get(int index)
	{
		return Sum(index) - Sum(index - 1);
	}
private:
	vector<ELE> m_vData;
};

class CTreeArrHlp
{
public:
	CTreeArrHlp(vector<int> nums)
	{
		sort(nums.begin(), nums.end());
		nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
		for (int i = 0; i < nums.size(); i++)
		{
			mValueToIndex[nums[i]] = i;
		}
		m_pTreeArr = new CTreeArr<int>(nums.size());
	}
	void Add(const int& val)
	{
		m_nums.emplace_back(val);
		m_pTreeArr->Add(mValueToIndex[val], 1);
	}
	int MoreCnt(const int& val)
	{
		return m_nums.size() - m_pTreeArr->Sum(mValueToIndex[val]);
	}
	vector<int> m_nums;
protected:
	CTreeArr<int>* m_pTreeArr;
	unordered_map<int, int> mValueToIndex;
	
};
class Solution {
public:
	vector<int> resultArray(vector<int>& nums) {
		CTreeArrHlp hlp1(nums), hlp2(nums);
		hlp1.Add(nums[0]);
		hlp2.Add(nums[1]);		
		for (int i = 2; i < nums.size(); i++)
		{
			const int i1 = hlp1.MoreCnt(nums[i]);
			const int i2 = hlp2.MoreCnt(nums[i]);
			if (i1 > i2)
			{
				hlp1.Add(nums[i]);
			}
			else if (i1 < i2)
			{
				hlp2.Add(nums[i]);
			}
			else
			{
				if (hlp1.m_nums.size() <= hlp2.m_nums.size())
				{
					hlp1.Add(nums[i]);
				}
				else
				{
					hlp2.Add(nums[i]);
				}
			}
		}
		hlp1.m_nums.insert(hlp1.m_nums.end(), hlp2.m_nums.begin(), hlp2.m_nums.end());
		return hlp1.m_nums;
	}
};

使用封装的离散类

template
class CTreeArr
{
public:
CTreeArr(int iSize) :m_vData(iSize + 1)
{

}
void Add(int index, ELE value)
{
	index++;
	while (index < m_vData.size())
	{
		m_vData[index] += value;
		index += index & (-index);
	}
}
ELE Sum(int index)
{
	index++;
	ELE ret = 0;
	while (index)
	{
		ret += m_vData[index];
		index -= index & (-index);
	}
	return ret;
}
ELE Get(int index)
{
	return Sum(index) - Sum(index - 1);
}

private:
vector m_vData;
};

class CDiscretize //离散化
{
public:
CDiscretize(vector nums)
{
sort(nums.begin(), nums.end());
nums.erase(std::unique(nums.begin(), nums.end()), nums.end());
for (int i = 0; i < nums.size(); i++)
{
m_mValueToIndex[nums[i]] = i;
}
}
int operator[](const int value)const
{
auto it = m_mValueToIndex.find(value);
if (m_mValueToIndex.end() == it)
{
return -1;
}
return it->second;
}
int size()const
{
return m_mValueToIndex.size();
}
protected:
unordered_map<int, int> m_mValueToIndex;
};
class CTreeArrHlp
{
public:
CTreeArrHlp(vector nums):m_dis(nums),m_treeArr(m_dis.size())
{
}
void Add(const int& val)
{
m_nums.emplace_back(val);
m_treeArr.Add(m_dis[val], 1);
}
int MoreCnt(const int& val)
{
return m_nums.size() - m_treeArr.Sum(m_dis[val]);
}
vector m_nums;
protected:
CDiscretize m_dis;
CTreeArr m_treeArr;

};
class Solution {
public:
vector resultArray(vector& nums) {
CTreeArrHlp hlp1(nums), hlp2(nums);
hlp1.Add(nums[0]);
hlp2.Add(nums[1]);
for (int i = 2; i < nums.size(); i++)
{
const int i1 = hlp1.MoreCnt(nums[i]);
const int i2 = hlp2.MoreCnt(nums[i]);
if (i1 > i2)
{
hlp1.Add(nums[i]);
}
else if (i1 < i2)
{
hlp2.Add(nums[i]);
}
else
{
if (hlp1.m_nums.size() <= hlp2.m_nums.size())
{
hlp1.Add(nums[i]);
}
else
{
hlp2.Add(nums[i]);
}
}
}
hlp1.m_nums.insert(hlp1.m_nums.end(), hlp2.m_nums.begin(), hlp2.m_nums.end());
return hlp1.m_nums;
}
};

测试用例

template<class T,class T2>
void Assert(const T& t1, const T2& t2)
{
	assert(t1 == t2);
}

template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{
	if (v1.size() != v2.size())
	{
		assert(false);
		return;
	}
	for (int i = 0; i < v1.size(); i++)
	{
		Assert(v1[i], v2[i]);
	}

}

int main()
{
	vector<int> nums = { 11,92,25,90 };
	{
		Solution sln;
		;
		auto res = sln.resultArray(nums);
		Assert({ 11,92,25,90 }, res);
	}
	
}

【离散化】【 树状树状 】100246 将元素分配到两个数组中-LMLPHP

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

【离散化】【 树状树状 】100246 将元素分配到两个数组中-LMLPHP

03-04 06:38