LeetCode 236. 二叉树的最近公共祖先 极限性能 0ms 6.7MB 击败10000%

LeetCode 236. 二叉树的最近公共祖先
给定一个二叉树, 找到该树中两个指定节点的最近公共祖先。

百度百科中最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

C++非递归算法,0ms 6.7MB 击败100% 无敌快。重复1000次只要4ms,击败10000%

显示详情 执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.7 MB, 在所有 C++ 提交中击败了100.00%的用户

显示详情
执行用时:8 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:13.9 MB, 在所有 C++ 提交中击败了98.99%的用户

执行用时:4 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:14 MB, 在所有 C++ 提交中击败了85.08%的用户

lowestCommonAncestor_my重复一【万】次算法,执行耗时一共48ms。
lowestCommonAncestor_other重复一千次算法,执行耗时一共296ms。
lowestCommonAncestor_other2重复一千次算法,执行耗时一共1880ms。
显然my算法比别人快50倍

/* 执行结果:
显示详情 执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:6.7 MB, 在所有 C++ 提交中击败了100.00%的用户

显示详情
执行用时:8 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:13.9 MB, 在所有 C++ 提交中击败了98.99%的用户

执行用时:4 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:14 MB, 在所有 C++ 提交中击败了85.08%的用户



lowestCommonAncestor_my重复一【万】次算法,执行耗时一共48ms。
lowestCommonAncestor_other重复一千次算法,执行耗时一共296ms。
lowestCommonAncestor_other2重复一千次算法,执行耗时一共1880ms。
显然my算法比别人快50倍

另外破坏root子节点,造成内存泄露,这样leetcode退出程序时销毁内存时跳过这些节点直接导致内存从14MB→10MB
事实上c++提交里内存低于13.7MB的全是有作弊嫌疑的。

因为本题测主要耗时在输入读取上(平均10ms) 读入和程序基本内存需要10MB
LCA算法耗时0ms 0MB内存
释放耗时未知(可能是1ms),需要4MB内存
*/

#define RuinTree 1   // 0或1,破坏树可节省内存
#define MyIO     1   // 0或1,自行IO
#define Repeat   1   // 1或1000 10000,用于测试算法重复多次以后和其他算法的差距
#define Implement lowestCommonAncestor_my
// lowestCommonAncestor_my / lowestCommonAncestor_other / lowestCommonAncestor_other2

#if 1
#pragma GCC optimize(3)
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("unroll-loops")
#endif

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
static TreeNode* stackForLCA[100];
static TreeNode* stackForExist[100];
static TreeNode* stackForExistB[100];

// 作者 凄临雨 superzmy
class Solution
{
public:

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if constexpr ((Repeat) > 1)
        {
            volatile int count = (Repeat) - 1;
            while (count)
                count -= Implement(root, p, q) != NULL;
            if (count != 0) throw(1);
        }
        auto ret = Implement(root, p, q);
        if constexpr (RuinTree) // 破坏root子节点,造成内存泄露,这样leetcode退出程序时销毁内存时跳过这些节点直接导致内存从14MB→10MB
        {
            root->left = NULL;
            root->right = NULL;
        }
        return ret;
    }
    static TreeNode* lowestCommonAncestor_my(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        if (root == p || root == q)
            return root;
        if (p == q)
            return p;
        if (auto x = exist2(p, q); x)
            return x;
        //if (exist(p, q)) // p下找q找到了
        //    return p;
        //else if (exist(q, p))
        //    return q;

        // 两点不互相包含

        // 一个栈,int&1 表示这个节点已展开,否则未展开。
        // 对于未展开的节点,变为展开,入栈其两个子节点,不断展开寻找p和q之一
        // 已展开的再被读取到,则弹出栈
        // 一旦找到p或q之一
        // 切换到另一种算法来使用这个栈:
        //   在未展开节点x里直接dps搜索other
        //   一旦x存在other
        //   则从x所在栈位置向前找一个已展开节点,即公共节点
        TreeNode** pStackTop;
        pStackTop = stackForLCA;

        *++pStackTop = root;
        
        while(pStackTop > stackForLCA)
        {
            TreeNode* cur = *pStackTop;
            if ((intptr_t)cur & 1) //表示节点展开过
            {
                pStackTop--;
            }    
            else //表示节点未展开过
            {
                (intptr_t&)*pStackTop |= 1;
    go_quick:
                __builtin_prefetch(cur->left);
                if (cur == p || cur == q)
                {
                    TreeNode* other;
                    other = (TreeNode*)((intptr_t)cur ^ (intptr_t)p ^ (intptr_t)q);
                    // 当前节点是p/q之一,接下来只要在目前栈上未展开的节点上找到other
                    // 然后那个时候栈的最右侧已展开节点,即公共父节点
                    while (--pStackTop > stackForLCA)
                    {
                        if (((intptr_t)*pStackTop & 1) == 0)
                            if (*pStackTop && (*pStackTop == other || exist(*pStackTop, other)))
                            {
                                while (--pStackTop > stackForLCA)
                                {
                                    if ((intptr_t)*pStackTop & 1)
                                        return (TreeNode*)(1 ^ (intptr_t)*pStackTop);
                                }
                            }
                    }
                }
                if (cur->right)
                    *++pStackTop = cur->right;
                if (cur->left)
                {
                    cur = cur->left;
                    (intptr_t&) *++pStackTop = 1 | (intptr_t)cur;
                    goto go_quick;
                }    
            }
        }
        return NULL;
    }

    static bool exist(TreeNode* node, TreeNode* p)
    {
        if (node->left == p)
            return true;
        else if (node->right == p)
            return true;
        
        TreeNode** pStackTop;
        pStackTop = stackForExist;
        if (node->right)
            *++pStackTop = node->right;
        if (node->left)
            *++pStackTop = node->left;
        
        while (pStackTop > stackForExist)
        {
            //if (! ((pStackTop - stackForExist) < sizeof(stackForExist) / sizeof(*stackForExist)) )
            //    throw(0);

            TreeNode* cur = *pStackTop--;
            if (cur->left == p || cur->right == p)
                return true;
            if (cur->right)
                *++pStackTop = cur->right;
            if (cur->left)
                *++pStackTop = cur->left;
        }

        return false;
    }
    static TreeNode* exist2(TreeNode* p, TreeNode* q)
    {
        if (p == q)
            return p;
        TreeNode** pStackTopP; pStackTopP = stackForExist;
        TreeNode** pStackTopQ; pStackTopQ = stackForExistB;
        *++pStackTopP = q;
        *++pStackTopQ = p;
        
        while (true)
        {
            //if (! ((pStackTop - stackForExist) < sizeof(stackForExist) / sizeof(*stackForExist)) )
            //    throw(0);
            if (pStackTopP > stackForExist)
            {
                TreeNode* cur = *pStackTopP--;
                if (cur->left == p || cur->right == p)
                    return q;
                if (cur->right)
                    *++pStackTopP = cur->right;
                if (cur->left)
                    *++pStackTopP = cur->left;
            }
            else
                goto go_searchQ_only;

            
            if (pStackTopQ > stackForExistB)
            {
                TreeNode* cur = *pStackTopQ--;
                if (cur->left == q || cur->right == q)
                    return p;
                if (cur->right)
                    *++pStackTopQ = cur->right;
                if (cur->left)
                    *++pStackTopQ = cur->left;
            }
            else
                goto go_searchP_only;
        }
        return NULL;
    go_searchQ_only:
        while (pStackTopQ > stackForExistB)
        {
            TreeNode* cur = *pStackTopQ--;
            if (cur->left == q || cur->right == q)
                return p;
            if (cur->right)
                *++pStackTopQ = cur->right;
            if (cur->left)
                *++pStackTopQ = cur->left;
        }
        return NULL;
    go_searchP_only:
        while (pStackTopP > stackForExist)
        {
            TreeNode* cur = *pStackTopP--;
            if (cur->left == p || cur->right == p)
                return q;
            if (cur->right)
                *++pStackTopP = cur->right;
            if (cur->left)
                *++pStackTopP = cur->left;
        }
        return NULL;
    }


    /
/
//             别人的实现,用于对比
/
/

static TreeNode* lowestCommonAncestor_other(TreeNode* root, TreeNode* p, TreeNode* q) {
    if(root==NULL) return NULL;
    if(root==p||root==q) return root;           //在同一支,父子孙节点

    TreeNode*left=lowestCommonAncestor_other(root->left, p, q);
    TreeNode*right=lowestCommonAncestor_other(root->right, p, q);

    if(left==NULL)  return right;
    else if(right==NULL) return left;
    else return root;    //root在p,q中间  (left!=NULL&&right!=NULL) 
}

static TreeNode* lowestCommonAncestor_other2(TreeNode* root, TreeNode* p, TreeNode* q) {
    if(root == NULL){
        return root;
    }
    stack<TreeNode*> s1;
    stack<TreeNode*> s2;
    TreeNode* cur1 = root;
    TreeNode* cur2 = root;
    TreeNode* prePop1 = root;
    TreeNode* prePop2 = root;
    s1.push(root);
    s2.push(root);
    while(cur1 != p){
        if(!cur1 -> left && !cur1 -> right){
            s1.pop();
            prePop1 = cur1;
            cur1 = s1.top();
            continue;
        } 
        if(prePop1 == cur1 -> right || (prePop1 == cur1 -> left && cur1 -> right == NULL)){
            s1.pop();
            prePop1 = cur1;
            cur1 = s1.top();
            continue;
        }  
        if(cur1 -> left == NULL || prePop1 == cur1 -> left){
            if(cur1 -> right){
                s1.push(cur1 -> right);
            }
            else{
                s1.pop();
                prePop1 = cur1;
            }
            cur1 = s1.top();
            continue;
        }
        if(cur1 -> left){
            s1.push(cur1 -> left);
        }
        cur1 = s1.top();
    }

    while(cur2 != q){
        if(!cur2 -> left && !cur2 -> right){
            s2.pop();
            prePop2 = cur2;
            cur2 = s2.top();
            continue;
        }
        if(prePop2 == cur2 -> right || (prePop2 == cur2 -> left && cur2 -> right == NULL)){
            s2.pop();
            prePop2 = cur2;
            cur2 = s2.top();
            continue;
        }
        if(cur2 -> left == NULL || prePop2 == cur2 -> left){
            if(cur2 -> right){
                s2.push(cur2 -> right);
            }
            else{
                s2.pop();
                prePop2 = cur2;
            }
            cur2 = s2.top();
            continue;
        }
        if(cur2 -> left){
            s2.push(cur2 -> left);
        }
        cur2 = s2.top();
    }      
    int l = s1.size() - s2.size();
    if(l > 0){
        while(l--){
            s1.pop();
        }
    }
    else{
        l = -l;
        while(l--){
            s2.pop();
        }
    }
    while(!s1.empty() && !s2.empty()){
        if(s1.top() == s2.top()){
            return s1.top();
        }
        else{
            s1.pop();
            s2.pop();
        }
    }
    return root;
}
};



#if MyIO

int mymain() {
    ofstream fout("user.out");
    static char buff[400000];
    size_t size = 0;
    size = fread(buff, 1, sizeof(buff) - 1, stdin);
    buff[size] = 0;

    char* p = buff;
    p++;
    static TreeNode allNodes[12000];

    while (true)
    {
        TreeNode* pNodeLast = allNodes;
        int parentNodeIndex = 1;
        int cur = *p++;
        bool sign = false;
        while (cur != ']')
        {
            if (cur == '-')
            {
                sign = true;
                cur = *p++;
            }    
            else if ('0' <= cur && cur <= '9')
            {
                int value = 0;
                do
                {
                    value = value * 10 + (cur - '0');
                    cur = *p++;
                } while ('0' <= cur && cur <= '9');

                TreeNode*& parentPChild = (&(allNodes[parentNodeIndex/2].left)) [parentNodeIndex&1];
                parentPChild = ++pNodeLast;
                pNodeLast->val = sign ? -value : value;
                pNodeLast->left = NULL;
                pNodeLast->right = NULL;
                parentNodeIndex++;
                sign = false;
            }
            else if (cur == 'n')
            {
                parentNodeIndex++;
                cur = p[4];
                p += 5;
            }
            else
                cur = *p++;
        }
        if constexpr (0)
            for (TreeNode* pNode = allNodes + 1; pNode <= pNodeLast; ++pNode)
                printf("%d %d %d\n", 
                    pNode->val, 
                    pNode->left ? pNode->left->val : -1,
                    pNode->right ? pNode->right->val : -1);
        int args[2] = {};
        int* pargs = args;
        TreeNode* pq[2] = {};
        while (cur)
        {
            if (cur == '-')
            {
                sign = true;
                cur = *p++;
            }    
            else if ('0' <= cur && cur <= '9')
            {
                int value = 0;
                do
                {
                    value = value * 10 + (cur - '0');
                    cur = *p++;
                } while ('0' <= cur && cur <= '9');
                *pargs++ = sign ? -value : value;
                sign = false;
                if (pargs - args == 2)
                    break;
            }
            else
                cur = *p++;
        }
        
        for (TreeNode* pNode = allNodes + 1; pNode <= pNodeLast; ++pNode)
        {
            if (pNode->val == args[0])
            {
                pq[0] = pNode;
                if (pq[1])
                    break;
            }    
            else if (pNode->val == args[1])
            {
                pq[1] = pNode;
                if (pq[0])
                    break;
            }
        }
        
        auto ret = Solution().lowestCommonAncestor(&allNodes[1], pq[0], pq[1])->val;
        fout << ret << endl;
        for(cur = *p++; cur != '['; cur = *p++)
            if (cur == 0)
                return 0;
    }
    return 0;
};
int main() {
    return mymain();
}
#define main main2


#endif


作者:凄临雨 zmy
链接:https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-tree/solution/cfei-di-gui-suan-fa-12msda-bai-99-by-qi-535rq/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值