Algorithm 按顺序N创建最大树
设A为n个不同整数的数组。设A的最大元素的指数为m。将A上的最大树定义为A条目的二叉树,其中根包含A的最大元素,左侧子项是A[0:m-1]上的最大树,右侧子项是A[m+1:n-1]上的最大树。设计了一个O(n)算法来构建max树Algorithm 按顺序N创建最大树,algorithm,tree,Algorithm,Tree,设A为n个不同整数的数组。设A的最大元素的指数为m。将A上的最大树定义为A条目的二叉树,其中根包含A的最大元素,左侧子项是A[0:m-1]上的最大树,右侧子项是A[m+1:n-1]上的最大树。设计了一个O(n)算法来构建max树 在我创建一个虚拟示例的情况下,结果表明给定的数组是max树的有序遍历,对于子树根的给定条件,它们应该是最大的 从理论上讲,在O(n)时间内进行排序似乎是不可能的,因为目前世界上还没有能够在O(n)时间内对条目进行排序的排序算法。任何一种经过调整的逻辑都可以建立在排序后的
在我创建一个虚拟示例的情况下,结果表明给定的数组是max树的有序遍历,对于子树根的给定条件,它们应该是最大的 从理论上讲,在O(n)时间内进行排序似乎是不可能的,因为目前世界上还没有能够在O(n)时间内对条目进行排序的排序算法。任何一种经过调整的逻辑都可以建立在排序后的条目上,只需要建立树 可以使用更糟糕的情况O(n2)执行正常的递归实现。我在编程面试书的元素中看到了同样的问题,他们并没有提供任何解决方案。也可能是打字错误 递归逻辑
CreateTree(start, end)
if start > end return null
Find index in array between start and end inclusive which contain max value
Create Node with index value
Node.left = CreateTree(start, index - 1);
Node.right = CreateTree(index + 1, end);
确实有可能在O(n)时间内完成。我还附加了测试用例,将我的解决方案与参考O(n logn)解决方案进行比较。要解决这个问题: 以下是几点观察:
#include <iostream>
#include <algorithm>
#include <vector>
#include <limits>
#include <cassert>
#include <stack>
#include <limits>
using namespace std;
struct Node {
int data;
Node* left, *right;
};
/******************** Solution Begin ***************************/
Node* Construct(const vector<int>& array) {
stack<Node*> S;
for (auto&& x : array) {
Node* node = new Node{x, nullptr, nullptr};
while (!S.empty() && (S.top()->data < x)) {
node->left = S.top();
S.pop();
}
if (!S.empty()) {
S.top()->right = node;
}
S.emplace(node);
}
Node* last_popped = nullptr;
while (!S.empty()) {
last_popped = S.top();
S.pop();
}
return last_popped;
}
/******************** Solution End ***************************/
Node* SlowConstructHelper(const vector<int>& array, int start, int end) {
if (start > end) return 0;
int m = start;
for (int i = start + 1; i <= end; i++) {
if (array[i] > array[m]) m = i;
}
Node* root = new Node;
root->data = array[m];
root->left = SlowConstructHelper(array, start, m - 1);
root->right = SlowConstructHelper(array, m + 1, end);
return root;
}
Node* SlowConstruct(const vector<int>& array) {
return SlowConstructHelper(array, 0, array.size() - 1);
}
bool IsEqualTree(Node* tree1, Node* tree2) {
if ((!tree1) && (!tree2)) return true;
if ((!tree1) || (!tree2)) return false;
return (tree1->data == tree2->data) &&
IsEqualTree(tree1->left, tree2->left) &&
IsEqualTree(tree1->right, tree2->right);
}
int main() {
const int kNumRuns = 1000;
const int kArraySize = 10000;
for (int run = 0; run < kNumRuns; run++) {
vector<int> array(kArraySize);
for (int i = 0; i < kArraySize; i++) array[i] = i; // Uniqueness guaranteed
random_shuffle(array.begin(), array.end());
Node* root1 = Construct(array);
Node* root2 = SlowConstruct(array);
assert(IsEqualTree(root1, root2));
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
结构节点{
int数据;
节点*左,*右;
};
/********************解决方案开始***************************/
节点*构造(常量向量和数组){
堆栈S;
用于(自动和x:array){
Node*Node=新节点{x,nullptr,nullptr};
而(!S.empty()&&(S.top()->数据左=S.top();
S.pop();
}
如果(!S.empty()){
S.top()->right=节点;
}
S.emplace(节点);
}
Node*last_popped=nullptr;
而(!S.empty()){
最后一次弹出=S.top();
S.pop();
}
返回上次弹出的窗口;
}
/********************溶液端***************************/
节点*SLOWCONSTRUCHTELPER(常量向量和数组、整数开始、整数结束){
如果(开始>结束)返回0;
int m=开始;
对于(int i=start+1;i数组[m])m=i;
}
Node*root=新节点;
根->数据=数组[m];
root->left=SlowConstructHelper(数组,开始,m-1);
根->右=慢速构造器(数组,m+1,结束);
返回根;
}
节点*SlowConstruct(常量向量和数组){
返回SlowConstructHelper(数组,0,array.size()-1);
}
布尔IsEqualTree(节点*tree1,节点*tree2){
if((!tree1)&(!tree2))返回true;
如果(!tree1)|(!tree2))返回false;
返回(tree1->data==tree2->data)&&
IsEqualTree(树1->左,树2->左)&&
IsEqualTree(树1->右侧,树2->右侧);
}
int main(){
常数int kNumRuns=1000;
常量int kArraySize=10000;
对于(int run=0;run
编辑:早期版本声称树是最大堆。将其更正为“最大堆属性”。这看起来像家庭作业;请先让我们看看你自己的想法。我早就离开学校了。所以没有家庭作业的压力。我仍在试图找出如何实现O(n)顺序。我们有两个分区。我们必须递归地在两个分区上构建max树。但是进一步的分区需要找到每个分区的最大值。每次扫描一次。如果我们知道如何存储未来潜在分区元素的索引,那么我们就完成了。但到目前为止,我们仍在想办法。请解释为什么输入应该是输入的最大树的有序遍历。它还会产生线性时间排序算法吗?对于每个节点,决定是先打印左子树还是右子树,然后打印节点本身,就像某种修改的postorder?输入是对输出最大树的按序遍历。我错过什么了吗?左子树后跟根,根是最大值,后跟右子树。这对两个子树都适用。使用堆栈的方法很好,谢谢。注意:树不是最大堆,因为堆是一个完整的二叉树,而这个问题中的树可能不完整。