如何计算最不常见的祖先算法的时间复杂度?

时间:2014-06-07 12:19:22

标签: c++ c algorithm time-complexity least-common-ancestor

我进入了一篇谈论LCA算法的文章,代码很简单 http://leetcode.com/2011/07/lowest-common-ancestor-of-a-binary-tree-part-i.html

// Return #nodes that matches P or Q in the subtree.
int countMatchesPQ(Node *root, Node *p, Node *q) {
  if (!root) return 0;
  int matches = countMatchesPQ(root->left, p, q) + countMatchesPQ(root->right, p, q);
  if (root == p || root == q)
    return 1 + matches;
  else
    return matches;
}

Node *LCA(Node *root, Node *p, Node *q) {
  if (!root || !p || !q) return NULL;
  if (root == p || root == q) return root;
  int totalMatches = countMatchesPQ(root->left, p, q);
  if (totalMatches == 1)
    return root;
  else if (totalMatches == 2)
    return LCA(root->left, p, q);
  else /* totalMatches == 0 */
    return LCA(root->right, p, q);
}

但我想知道如何计算算法的时间复杂度,任何人都可以帮助我吗?

2 个答案:

答案 0 :(得分:4)

LCA的复杂性为O(h),其中h是树的高度。树高的上限为O(n),其中n表示树中顶点/节点的数量。

如果您的树是平衡的(请参阅AVLred black tree),则高度为log(n)的顺序,因此算法的总复杂度为O(log(n))

答案 1 :(得分:3)

此算法的最坏情况是节点是兄弟节点离开节点。

Node *LCA(Node *root, Node *p, Node *q)
{
  for root call countMatchesPQ;
  for(root->left_or_right_child) call countMatchesPQ; /* Recursive call */
  for(root->left_or_right_child->left_or_right_child) call countMatchesPQ;
  ...
  for(parent of leave nodes of p and q) call countMatchesPQ;
}
countMatchesPQ调用

height of tree times - 1。将树的调用高度设为h

现在检查辅助函数的复杂性

int countMatchesPQ(Node *root, Node *p, Node *q) {
  Search p and q in left sub tree recursively
  Search p and q in right sub tree recursively
}

因此,这是一次广泛的搜索,最终的复杂性为N,其中N是树中节点的数量。

添加两个观察值,算法的总复杂度为

O(h * N)

如果树是平衡的,h = log N(RB树,treap等) 如果树不平衡,则更糟糕 h may be up to N

因此N的复杂性可以作为

给出
  

对于平衡二叉树:O(N logN)
  更准确地说,它是实际的h(N + N / 2 + N / 4 ...)   用于平衡树,因此应该来2hN
  对于不平衡二叉树:O(N 2
  更准确地说,它是实际的h(N + N-1 + N-2 ......)   用于平衡树,因此应该来h x N x(N + 1)/ 2

因此,更糟糕的案例复杂性是N 2

您的算法不使用任何内存。通过使用一些内存来保存路径,您可以大大改善算法。