LeetCode騰訊精選50題算法【二叉搜索樹的最近公共祖先】

最近幾周摻雜着需求、以及一些瑣碎的事情,算法的學習一直都是默默的在搞,沒有形成文章。

或許是我懶惰了;或許是我鬆懈了;或許是我不重視了;但是,我還在。學習可能會因爲工作推遲,但絕不會遲到,所以,還請各位放心,該有的都會到來。

之前也在有些羣裏看到算法的持續學習,我自己又找了一個方式來攻克LeetCode上的題目,先從騰訊精選練習(50題) 開始,之前有完成過一些,不過都是整合在ARTS打卡里,也沒細說。現在是一個系列,還有機會學習噠。

Algorithm LeetCode算法

235. 二叉搜索樹的最近公共祖先
(https://leetcode-cn.com/problems/lowest-common-ancestor-of-a-binary-search-tree/)

題目描述:給定一個二叉搜索樹,找到該樹中兩個指定節點的最近公共祖先。

百度百科中最近公共祖先的定義爲:“對於有根樹 T 的兩個結點p、q,最近公共祖先表示爲一個結點 x,滿足 x 是 p、q 的祖先且 x 的深度儘可能大(一個節點也可以是它自己的祖先)。”

      6
   /    \
  2      8    
 / \    /  \
0   4  7    9
   / \
  3   5

示例1:

輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
輸出: 6 
解釋: 節點 2 和節點 8 的最近公共祖先是 6。

示例2:

輸入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
輸出: 2
解釋: 節點 2 和節點 4 的最近公共祖先是 2, 因爲根據定義最近公共祖先節點可以爲節點本身。

在題解之前,我們還是有必要知道二叉搜索樹是一顆什麼樣的樹,都有什麼特點。

二叉搜索樹(Binary Search Tree),又(二叉查找樹,二叉排序樹)它或者是一顆空樹,或者是具有下列性質的二叉樹:

  1. 若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;
  1. 若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;
  1. 它的左、右子樹分別爲二叉排序樹。

最近公共祖先: 是距離兩個節點最近的公共祖先節點。在這裏最近考慮的是節點的深度。

比如,在我們這顆二叉樹中

  1. 如果p是2,q是8的情況,分別在跟節點的左右兩邊,則最近的公共節點就是他們的根節點,即6;
  2. 如果p是2,q是7的情況,因爲還是分別在6這個根節點的左右兩邊,那最近的公共節點還是6;
  3. 如果p是2,q是4的情況,2和4在節點2的右子樹上,即最小公共節點就是2自己了(一個節點也可以是它自己的祖先)
  4. 如果p是2,q是0的情況,2和0在節點2的左子樹上,即最小公共節點還是2自己

好了,搞清楚了各種情況,接下來的解法肯定就難不倒我們了。寫代碼是建立在思路清晰的基礎上,對吧。

解法:遞歸

  1. 從根節點開始遍歷
  1. 倘若p和q都在右子樹上,則以右孩子爲根節點繼續1的操作
  1. 倘若p和q都在左子樹上,則以左孩子爲根節點繼續1的操作
  1. 如果步驟2和步驟3均不成立,則說明我們已經找到答案

將二叉樹構建完成:

// 將二叉樹構建完成
public static void main(String[] args) {
	TreeNode treeNode = new TreeNode(6);
	treeNode.left = new TreeNode(2);
	treeNode.left.left = new TreeNode(0);
	treeNode.left.right = new TreeNode(4);
	treeNode.left.right.left = new TreeNode(3);
	treeNode.left.right.right = new TreeNode(5);
		
	treeNode.right = new TreeNode(8);
	treeNode.right.left = new TreeNode(7);
	treeNode.right.right = new TreeNode(9);
		
	TreeNode treeNode2 = lowestCommonAncestor(treeNode, new TreeNode(2), new TreeNode(8));
	System.out.println(treeNode2);
}

遞歸查找二叉樹:

public static TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
	int parent = root.val;
		
	int pValue = p.val;
		
	int qValue = q.val;
		
	// 如果兩個值都大於跟節點,則從右子樹查找
	if (pValue > parent &&qValue > parent) {
		return lowestCommonAncestor(root.right, p, q);
	// 如果兩個值都小於跟節點,則從左子樹查找
	} else if (pValue < parent && qValue < parent) {
		return lowestCommonAncestor(root.left, p, q);
	// 上述兩種情況均沒有,則得到答案
	} else {
		return root;
	}     
}

這裏僅僅舉例說明了通過遞歸的方式來解題,基本上也都能解決二叉樹相關的問題。但是,就這樣就夠了嗎?其實並沒有,二叉樹也有自己的特性,有時候是不需要通過遞歸來解決的。

在我們這個題解裏,時間複雜度是O(N),空間複雜度是O(N),時間複雜度沒辦法了,N是節點中的個數,在最壞的情況下我們是需要訪問所有的節點,但是我們可以優化空間複雜度。

遞歸的時候,額外空間主要是棧產生的,N就是二叉樹的高度,最壞情況下就是訪問所有的,但是我們可以通過另一種方式來優化,空間複雜度可以達到O(1)。歡迎在留言區和我互動,至於寫法,我會在知識星球給出,加入星球的小夥伴直接去看就行啦。

結語

二叉搜索樹,算是對二叉樹的一個延伸了,但是呢,解題的思路還是大同小異,無非就是二叉搜索樹更加有自己的特點,我們操作起來反而會目的性更明確一些,也更好去理解。

LeetCode真的是一個好的學習社區,無論在誰的眼裏,都是學習算法的好去處。小編也無數次的說過,算法就是一個持續學習的過程,只要持續學習,持續練習,持續寫代碼,你就能懂其中的解法,對於我們程序員的思維來說,是一個極大的提升,歡迎和大家一起學習。

我們的矩陣公衆號:奔跑吧攻城獅

簡介:專注於IT開發,和你聊聊職場話題,侃侃球,在休閒和知識的海洋裏遨遊

社羣slogan:社羣是小家,成長靠大家;人人共參與,攜手圖共贏

個人slogan:當你的才華還無法撐起你的野心時候,那應該靜下心來好好學習

發佈了115 篇原創文章 · 獲贊 44 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章