国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

力扣236——二叉樹(shù)的最近公共祖先

這篇具有很好參考價(jià)值的文章主要介紹了力扣236——二叉樹(shù)的最近公共祖先。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

祝大家新年快樂(lè)呀,雖這段時(shí)間正值過(guò)年,但是我們不要忘記停下學(xué)習(xí)的腳步。今天我們一起看一到力扣上的經(jīng)典二叉樹(shù)OJ題,求二叉樹(shù)兩個(gè)結(jié)點(diǎn)最近的公共祖先。

https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/description/

鏈接給大家放在這里啦,大家一點(diǎn)即達(dá)

力扣236——二叉樹(shù)的最近公共祖先,leetcode,算法首先我們看到題目,這道題并沒(méi)有告訴我們這是一棵怎么樣的二叉樹(shù),不是完全二叉,也不是搜索二叉,所以這道題做起來(lái)就比較棘手,完全二叉樹(shù)的話我們可以根據(jù)結(jié)點(diǎn)的編號(hào)查找,搜索二叉我們也可以按照大小確定范圍,但是眼前這顆數(shù)完全是一個(gè)亂序的,所以這道題怎么下手呢?

方法一? ? ? ??

我們不妨先確定要查找的兩個(gè)結(jié)點(diǎn)在根結(jié)點(diǎn)的哪邊,我們拿5和8舉例子

力扣236——二叉樹(shù)的最近公共祖先,leetcode,算法很明顯。這兩個(gè)結(jié)點(diǎn)一個(gè)在根結(jié)點(diǎn)的左邊,一個(gè)在右邊,所以他們最近公共結(jié)點(diǎn)肯定就是根節(jié)點(diǎn)。

那如果在同一邊呢?比如6和4,

力扣236——二叉樹(shù)的最近公共祖先,leetcode,算法結(jié)點(diǎn)6和4都在根節(jié)點(diǎn)的左子樹(shù)上,我們可以用剛才的方法,遞歸根節(jié)點(diǎn)的左子樹(shù),以結(jié)點(diǎn)5為跟,就可以求出他們最近的公共結(jié)點(diǎn)為5;思路有了,現(xiàn)在我們編寫(xiě)代碼

我們先封裝一個(gè)函數(shù)判斷結(jié)點(diǎn)是否在這個(gè)以root為根結(jié)點(diǎn)的二叉樹(shù)內(nèi):

bool IsTree(TreeNode*root,TreeNode* x)
    {
        if(root==nullptr)
        {
            return false;
        }
        return root==x||IsTree(root->left,x)||IsTree(root->right,x);
    }

然后我們?cè)诮o定的函數(shù)內(nèi)實(shí)現(xiàn)出這個(gè)函數(shù)。

這里教大家一個(gè)簡(jiǎn)便的方法。我們定義幾個(gè)bool變量:

bool Leftp,Rightp,Leftq,Rightq;//依次代表的含義是p在左子樹(shù),P在右子樹(shù),q在左子樹(shù),q在右子樹(shù)

然后我們?nèi)フ襭在root的那一邊,把返回值給Leftp,讓Rightp=!Left;

Leftp=IsTree(root->left,p);
Rightp=!Leftp;

這樣寫(xiě)大家能理解什么意思嗎?在root的左子樹(shù)去找結(jié)點(diǎn)p的結(jié)果賦給Leftp,不管是不是在左邊,右邊的結(jié)果肯定就是!Leftp,假如Leftp是true,那Rightp就是false;如果Leftp是false,那Rightp就是true;二者肯定一真一假,判斷q結(jié)點(diǎn)在哪邊也是如此

Leftq=IsTree(root->left,q);
Rightq=!Leftq;

然后我們判斷如果兩個(gè)結(jié)點(diǎn)pq有一個(gè)是根節(jié)點(diǎn)root的話,那就返回root就可以了

if(p==root||q==root)
        {
            return root;
        }

其次,判斷,如果pq一個(gè)在根節(jié)點(diǎn)左邊,一個(gè)在右邊,那還是返回根節(jié)點(diǎn)。即

if((Leftp&&Rightq)||(Rightp&&Leftq))//中間用||連接是因?yàn)槲覀円膊恢浪麄冊(cè)谀倪?,反正肯定有一組是真的
{
    return root;
}

然后再判斷他們?cè)谕贿叺那闆r,代碼運(yùn)行到這里,肯定能證明他們不在同一邊,我們先判斷同時(shí)在左子樹(shù)的情況:

        else if(Leftp&&Leftq)
        {
            return lowestCommonAncestor(root->left,p,q);
        }

剩下的就是同時(shí)在右子樹(shù)的情況:

else{
        return lowestCommonAncestor(root->right,p,q);
    }

然后我們提交,就可以看到通過(guò)啦。但是我們思考一下,這樣的寫(xiě)法時(shí)間復(fù)雜度是很大的。如果這棵樹(shù)是一個(gè)類(lèi)似于單邊的二叉樹(shù),也就是另外一邊的結(jié)點(diǎn)個(gè)數(shù)很少很少,幾乎全部集中在一邊,且要找的兩個(gè)結(jié)點(diǎn)都在最后,即:

力扣236——二叉樹(shù)的最近公共祖先,leetcode,算法

我們要查找的兩個(gè)結(jié)點(diǎn)在這個(gè)位置,它的時(shí)間復(fù)雜度是多少?可以看到,我們以3為根結(jié)點(diǎn)查詢(xún)1和3在哪邊需要走N-2次+N-3次,然后遞歸以10為根節(jié)點(diǎn)查找,再遞歸以8為根節(jié)點(diǎn)查找.......時(shí)間復(fù)雜度其實(shí)是O(N^2)的。

bool IsTree(TreeNode*root,TreeNode* x)
    {
        if(root==nullptr)
        {
            return false;
        }
        return root==x||IsTree(root->left,x)||IsTree(root->right,x);
    }
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        bool Leftp,Rightp,Leftq,Rightq;
        Leftp=IsTree(root->left,p);
        Rightp=!Leftp;
        Leftq=IsTree(root->left,q);
        Rightq=!Leftq;
        if(p==root||q==root)
        {
            return root;
        }
        if((Leftp&&Rightq)||(Rightp&&Leftq))
        {
            return root;
        }
        else if(Leftp&&Leftq)
        {
            return lowestCommonAncestor(root->left,p,q);
        }
        else{
            return lowestCommonAncestor(root->right,p,q);
        }
}

方法二

下面我們介紹第二種方法

第二種方式是我們記錄兩個(gè)結(jié)點(diǎn)的路徑,即從根結(jié)點(diǎn)到找到他們之間所有的結(jié)點(diǎn)。例如:

力扣236——二叉樹(shù)的最近公共祖先,leetcode,算法

結(jié)點(diǎn)6的路徑是3->5->6,結(jié)點(diǎn)4的路徑是3->5->2->4,把他們都放在兩個(gè)棧里面,比較棧的特點(diǎn)是后進(jìn)先出,然后比較這個(gè)兩個(gè)棧的第一個(gè)相同的棧頂元素。這樣的話我們最壞無(wú)非就是遍歷2次這棵樹(shù)就可以,定義兩個(gè)棧,算是以空間換時(shí)間。下面我們開(kāi)始實(shí)現(xiàn)

我們首先需要在原函數(shù)定義兩個(gè)棧,一個(gè)用于存放p結(jié)點(diǎn)的路徑,一個(gè)存放q結(jié)點(diǎn)的路徑

TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
stack<TreeNode*> ppath;
stack<TreeNode*>qpath;
}

然后我們需要封裝一個(gè)函數(shù)用來(lái)求結(jié)點(diǎn)走過(guò)的路徑Getpath();參數(shù)需要根節(jié)點(diǎn),待求結(jié)點(diǎn),棧,即

bool Getpath(TreeNode* root, TreeNode* x, stack<TreeNode*>& path)//傳引用是為了我們?cè)谡{(diào)用這個(gè)函數(shù)時(shí)對(duì)這個(gè)棧的修改可以隨時(shí)生效,不需要再拷貝

用bool類(lèi)型是為了我們找到這個(gè)結(jié)點(diǎn)時(shí)就直接返回不再往下走。

下面我們實(shí)現(xiàn)這個(gè)函數(shù),首先判斷根節(jié)點(diǎn)為空,那就返回false,接下來(lái)先把根節(jié)點(diǎn)入棧,然后判斷根結(jié)點(diǎn)是要求的路徑的結(jié)點(diǎn),是的話返回true;

bool Getpath(TreeNode* root, TreeNode* x, stack<TreeNode*>& path)
{
	if (root == nullptr)
	{
		return false;
	}
	path.push(root);
	if (root == x)
	{
		return true;
	}
}

代碼走到這里,那就證明根結(jié)點(diǎn)不是x,我們遞歸左子樹(shù),如果左子樹(shù)為真,返回true;左子樹(shù)遇到空結(jié)點(diǎn)返回false,下來(lái)遞歸右子樹(shù),右子樹(shù)也是如此;

if (Getpath(root->left, x, path))
		return true;
	
	if (Getpath(root->right, x, path))
		return true;

代碼走到這里,證明根節(jié)點(diǎn)及它的左右孩子結(jié)點(diǎn)都不是x,我們需要把這個(gè)根節(jié)點(diǎn)出棧的,比如:

力扣236——二叉樹(shù)的最近公共祖先,leetcode,算法

比如我們求結(jié)點(diǎn)4的路徑,代碼運(yùn)行到查找5的左孩子時(shí),6先進(jìn)棧,然后遞歸6的左右子樹(shù),都為空,已經(jīng)把6的左右子樹(shù)都查找完畢,所以4的路徑不經(jīng)過(guò)結(jié)點(diǎn)6,那這個(gè)時(shí)候需要讓6出棧,然后返回false,返回上一層遞歸。

if (root != x)
	{
		path.pop();
	}
	return false;

這個(gè)函數(shù)就封裝完成。

下面寫(xiě)原函數(shù),原函數(shù)我們首先要定義兩個(gè)棧,上面已經(jīng)定義過(guò),這個(gè)是我們先走一遍p的路徑,再走一遍q的路徑,這個(gè)時(shí)候ppath和qpath兩個(gè)棧里面存放著p和q的路徑,我們需要讓這兩個(gè)棧的大小相等,因?yàn)閺母?jié)點(diǎn)到最近公共祖先肯定是完全一樣的,這樣才能找出公共路徑。

while (ppath.size() != qpath.size())
{
	if (ppath.size() > qpath.size())
		ppath.pop();
	else
		qpath.pop();
}

這個(gè)時(shí)候兩棧存放的數(shù)據(jù)個(gè)數(shù)相等,只需比較棧頂元素是否相等,不相等再同時(shí)出棧,相等時(shí)返回棧頂元素就可以啦。

while (ppath.top() != qpath.top())
{
	ppath.pop();
	qpath.pop();
}
return ppath.top();

這樣代碼就能提交過(guò)啦。時(shí)間復(fù)雜度也很樂(lè)觀。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-829764.html

bool Getpath(TreeNode* root, TreeNode* x, stack<TreeNode*>& path)
{
	if (root == nullptr)
	{
		return false;
	}
	path.push(root);
	if (root == x)
	{
		return true;
	}
	if (Getpath(root->left, x, path))
		return true;;
	
	if (Getpath(root->right, x, path))
		return true;
	if (root != x)
	{
		path.pop();
	}
	return false;
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
    stack<TreeNode*> ppath;
stack<TreeNode*>qpath;
Getpath(root, p, ppath);
Getpath(root, q, qpath);
while (ppath.size() != qpath.size())
{
	if (ppath.size() > qpath.size())
		ppath.pop();
	else
		qpath.pop();
}
while (ppath.top() != qpath.top())
{
	ppath.pop();
	qpath.pop();
}
return ppath.top();
    }

到了這里,關(guān)于力扣236——二叉樹(shù)的最近公共祖先的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包