【C++动态规划 排序】823. 带因子的二叉树|1899
本文涉及知识点
C++动态规划 排序
LeetCode823. 带因子的二叉树
给出一个含有不重复整数元素的数组 arr ,每个整数 arr[i] 均大于 1。
用这些整数来构建二叉树,每个整数可以使用任意次数。其中:每个非叶结点的值应等于它的两个子结点的值的乘积。
满足条件的二叉树一共有多少个?答案可能很大,返回 对 109 + 7 取余 的结果。
示例 1:
输入: arr = [2, 4]
输出: 3
解释: 可以得到这些二叉树: [2], [4], [4, 2, 2]
示例 2:
输入: arr = [2, 4, 5, 10]
输出: 7
解释: 可以得到这些二叉树: [2], [4], [5], [10], [4, 2, 2], [10, 2, 5], [10, 5, 2].
提示:
1 <= arr.length <= 1000
2 <= arr[i] <= 109
arr 中的所有值 互不相同
动态规划 排序
所有节点的值>1,父亲节点值=两个子节点的值的积。
→
\rightarrow
→ 父节点的值 > 子节点的值。
nums升序排序,mIndex记录nums[i] To i。
next[i] 记录所有符合条件的{j,k} nums[i] = nums[j]*nums[k]
动态规划的状态表示
dp[i]表示以值的编号为i为根的二叉树数量。
动态规划的填表顺序
i从0到N-1处理,这样可以保子树已经处理完。
动态规划的转移方程
dp[i]=1
for([j,k] : next[i])
dp[i] += dp[j]*dp[k];
动态规划初始值
dp全为0
动态规划的返回值
dp之和。
代码
核心代码
template<int MOD = 1000000007>
class C1097Int
{
public:
C1097Int(long long llData = 0) :m_iData(llData% MOD)
{
}
C1097Int operator+(const C1097Int& o)const
{
return C1097Int(((long long)m_iData + o.m_iData) % MOD);
}
C1097Int& operator+=(const C1097Int& o)
{
m_iData = ((long long)m_iData + o.m_iData) % MOD;
return *this;
}
C1097Int& operator-=(const C1097Int& o)
{
m_iData = (m_iData + MOD - o.m_iData) % MOD;
return *this;
}
C1097Int operator-(const C1097Int& o)
{
return C1097Int((m_iData + MOD - o.m_iData) % MOD);
}
C1097Int operator*(const C1097Int& o)const
{
return((long long)m_iData * o.m_iData) % MOD;
}
C1097Int& operator*=(const C1097Int& o)
{
m_iData = ((long long)m_iData * o.m_iData) % MOD;
return *this;
}
C1097Int operator/(const C1097Int& o)const
{
return *this * o.PowNegative1();
}
C1097Int& operator/=(const C1097Int& o)
{
*this /= o.PowNegative1();
return *this;
}
bool operator==(const C1097Int& o)const
{
return m_iData == o.m_iData;
}
bool operator<(const C1097Int& o)const
{
return m_iData < o.m_iData;
}
C1097Int pow(long long n)const
{
C1097Int iRet = 1, iCur = *this;
while (n)
{
if (n & 1)
{
iRet *= iCur;
}
iCur *= iCur;
n >>= 1;
}
return iRet;
}
C1097Int PowNegative1()const
{
return pow(MOD - 2);
}
int ToInt()const
{
return m_iData;
}
private:
int m_iData = 0;;
};
class Solution {
public:
int numFactoredBinaryTrees(vector<int>& arr) {
const int N = arr.size();
sort(arr.begin(), arr.end());
unordered_map<int, int> mIndex;
for (int i = 0; i < arr.size(); i++) {
mIndex[arr[i]] = i;
}
vector<vector<pair<int, int>>> next(N);
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
long long tmp = (long long)arr[i] * arr[j];
if ((tmp <= INT_MAX) && mIndex.count(tmp)) {
next[mIndex[tmp]].emplace_back(i, j);
}
}
}
vector<C1097Int<>> dp(N);
for (int i = 0; i < N; i++) {
dp[i] = 1;
for (auto [j, k] : next[i]) {
dp[i] += dp[j] * dp[k];
}
}
auto ans = accumulate(dp.begin(), dp.end(), C1097Int<>());
return ans.ToInt();
}
};
单元测试
vector<int> arr;
TEST_METHOD(TestMethod1)
{
arr = { 2, 4 };
auto res = Solution().numFactoredBinaryTrees(arr);
AssertEx(3, res);
}
TEST_METHOD(TestMethod2)
{
arr = { 2, 4, 5, 10 };
auto res = Solution().numFactoredBinaryTrees(arr);
AssertEx(7, res);
}
扩展阅读
我想对大家说的话 |
---|
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
如果程序是一条龙,那算法就是他的是睛 |
失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。