这个算法的运行时间复杂度是多少?你是如何分析的

What is the running time complexity of this algorithm? And HOW do you do the analysis for it?

本文关键字:多少 运行 时间复杂度 算法      更新时间:2023-10-16

-下面的lowestCommonAncestor函数在二进制树中查找两个节点pq的最低公共祖先(假设两个节点都存在并且所有节点值都是唯一的(。

class Solution {
public:
bool inBranch(TreeNode* root, TreeNode* node)
{
if (root == NULL)
return false;
if (root->val == node->val)
return true;
return (inBranch(root->left, node) || inBranch (root->right, node));
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == NULL)
return NULL;
if (root->val == p->val || root->val == q->val)
return root;
bool pInLeftBranch = false;
bool qInLeftBranch = false;
pInLeftBranch = inBranch (root->left, p);
qInLeftBranch = inBranch (root->left, q);
//Both nodes are on the left
if (pInLeftBranch && qInLeftBranch)
return lowestCommonAncestor(root->left, p, q);
//Both nodes are on the right
else if (!pInLeftBranch && !qInLeftBranch)
return lowestCommonAncestor(root->right, p, q);
else 
return root;
}
};

每次调用inBranch(root, node)时,都会添加O(root的子代数((请参阅二进制树搜索的时间复杂性(。我将假设二叉树在第一次计算时间复杂性时是平衡的,然后看看树不平衡的最坏情况。

场景1:平衡树

一个节点的子节点数量大约是其父节点的一半。因此,每次我们递归,对inBranch的调用都将花费一半的代价。假设N是树中节点的总数。在对lowestCommonAncestor的第一次调用中,我们搜索所有N个节点。在随后的通话中,我们搜索左半部分或右半部分,依此类推

O(N+N/2+N/4…(仍然与O(N(相同。

场景2:不平衡树

假设这棵树非常不平衡,以至于所有的孩子都在左边:

A
/
B
/
C
/
etc...

每个递归级别的子体数量仅减少1。因此,我们的时间复杂性看起来像:

O(N+(N-1(+(N-2(+…+2+1(,相当于O(N^2(。

有更好的方法吗

如果这是一个二进制搜索树,我们可以做得和O一样好(path_length(p(+path_lengh(q((。如果没有,您总是需要遍历整个树至少一次:O(N(以找到每个节点的路径,但您仍然可以改进最坏的情况。我把它留给你来计算实际的算法!

在最坏的情况下,二叉树是一个长度为N的列表,其中每个节点最多有一个子节点,而pq是相同的叶节点。在这种情况下,您将有一个运行时间O(N^2):您在树下的每个节点上调用inBranch(运行时O(N)(。

如果二叉树是平衡的,则这将变为具有N节点的O(N log(N)),因为您可以将O(2^K)节点放入深度为K的树中(最多递归K次(:查找每个节点是O(N),但最多只重复log(N)查看Ben Jones的回答

请注意,更好的算法会定位每个节点一次,并存储树下的路径列表,然后比较路径。查找树中的每个节点(如果它未排序(必然是最坏情况O(N),列表比较也是O(N)(不平衡情况(或O(log(N))(平衡情况(,因此总运行时间是O(N)。你可以在排序后的树上做得更好,但这显然不是既定的。