编辑:问题实际上是算法(感谢molbdnilo下面的回答)失败的情况是O(N2) - >二次。下面的人实际上试图找到一个真正的最坏情况O(N Log(N))时间复杂度算法。
我参加了本月的抄袭挑战。我花了大约一个小时来获得100%正确的O(N Log(N))时间复杂度算法。
但是你可以在下面看到我的性能达到了75%,因为其中一项测试需要花费10倍才能运行。我不明白为什么! 你能指出我的错误吗?
第2点包含我的解决方案的完整问题描述和完整报告(测试用例和时间)。
粗略地说,我逐条添加每根绳子并从添加的节点位置更新根(祖先)的路径,新的最大权重可以在每个祖先的“下/下”添加。
以下是代码:
// you can use includes, for example:
#include <algorithm>
#include <vector>
#include <map>
#include <iostream>
using namespace std;
// you can write to stdout for debugging purposes, e.g.
// cout << "this is a debug message" << endl;
struct node
{
int max_to_add;
int id;
node* mummy;
};
std::map< int, node* > nodes;
bool insertRope( int durability, int pos, int Id, int weight )
{
node* n = new node;
n->id = Id;
nodes[Id] = n;
if( pos == -1 )
{
n->max_to_add = durability - weight;
n->mummy = NULL;
if( n->max_to_add < 0 ) return false;
}
else
{
std::map< int, node* >::iterator it = nodes.find(pos);
if( it != nodes.end() )
{
node* parent = (*it).second;
n->mummy = parent;
n->max_to_add = std::min( ( parent->max_to_add - weight), (durability - weight) ) ;
if( n->max_to_add < 0 ) return false;
node* current = n;
while ( (current = current->mummy) != NULL )
{
current->max_to_add = current->max_to_add - weight;
if( current->max_to_add < 0 )
{
return false;
}
}
}
}
return true;
}
int solution(vector<int> &A, vector<int> &B, vector<int> &C) {
// write your code in C++11
for(int i = 0; i < A.size() ; ++i)
{
if( insertRope( A[i], C[i],i,B[i] ) == false ) {return i;}
}
return A.size();
}
int main()
{
/*static const int arrA[] = {4, 3, 1};
vector<int> vecA (arrA, arrA + sizeof(arrA) / sizeof(arrA[0]) );
static const int arrB[] = {2, 2, 1};
vector<int> vecB (arrB, arrB + sizeof(arrB) / sizeof(arrB[0]) );
static const int arrC[] = {-1, 0, 1};
vector<int> vecC (arrC, arrC + sizeof(arrC) / sizeof(arrC[0]) );
*/
static const int arrA[] = {5, 3, 6, 3, 3};
vector<int> vecA (arrA, arrA + sizeof(arrA) / sizeof(arrA[0]) );
static const int arrB[] = {2, 3, 1, 1, 2};
vector<int> vecB (arrB, arrB + sizeof(arrB) / sizeof(arrB[0]) );
static const int arrC[] = {-1, 0, -1, 0, 3};
vector<int> vecC (arrC, arrC + sizeof(arrC) / sizeof(arrC[0]) );
int sol = solution(vecA,vecB,vecC);
system("PAUSE");
return 0;
}
编辑1: 根据Rafid的建议我使用new [],更好,但我仍然有perf问题: https://codility.com/cert/view/certRT5YDP-W65HGPF28B5RN5AY/details
答案 0 :(得分:1)
我可以指出的一个性能提示是:避免重复使用'new'运算符,因为它很昂贵。您可以创建一个大的内存块,然后在需要时使用它,这样就不会在堆中重复分配内存。
答案 1 :(得分:0)
免责声明:我并非100%确定这是导致您出现问题的原因。
请注意,您执行非常糟糕的情况如下: “行”配置中的100K项目。
如果你看看你的while循环,你会发现你的算法没有提供O(NlogN)最坏情况的复杂性。最糟糕的情况是所有绳索都是对齐的,每次添加节点时都必须遍历整个树以更改max_to_add
这并没有改变这样一个事实:你可能(正如在一些评论中所建议的那样)单独使用std :: map而没有指针,这可能会提供更好的性能,因为你不需要new
分配每次创建节点时,都会在堆栈上创建它们。也许甚至使用std :: unordered_map。
编辑:
好的,我找到了一种更好的复杂性。您不需要更新所有绳索的负载,只需要在树上的叶子节点上维护正确的值。此值应该是此分支上节点的max_to_add
的最小值。
我会尽可能发布一些代码。
答案 2 :(得分:0)
如果我们只是跳过将元素添加到地图并尝试计算节点的当前容量,该怎么办?现在很难检查它,但这是代码,它显示了这个想法。
bool process_node(std::vector<int> &A, std::vector<int> &B, std::vector<int> &C, int index) {
int next_parent = C[index];
A[index] -= B[index];
while(next_parent != -1) {
A[next_parent] -= B[index];
if (A[next_parent] < 0) {
return false;
}
next_parent = C[next_parent];
}
return true;
}
int solution(std::vector<int> &A, std::vector<int> &B, std::vector<int> &C) {
for (int i = 0; i < A.size(); ++i) {
if (!process_node(A, B, C, i)) {
return i;
}
}
return A.size();
}
看起来像O(NlogN)
时间,因为我们在树中进行N次父查找。也许我们可以避免一些额外的遍历。