精品推薦:
《征服數(shù)據(jù)結(jié)構(gòu)》專欄:50多種數(shù)據(jù)結(jié)構(gòu)徹底征服 《經(jīng)典圖論算法》專欄:50多種經(jīng)典圖論算法全部掌握 最近一網(wǎng)友發(fā)文稱:為什么大家本科畢業(yè)月薪都是二三十k,而自己只有十幾k。實(shí)際上這是一種錯(cuò)覺,本科畢業(yè)月薪二三十k實(shí)際上是很少的,我們?cè)诰W(wǎng)上經(jīng)常會(huì)看到應(yīng)屆生在各大廠的開獎(jiǎng)年薪動(dòng)輒30多萬,40多萬,有的甚至更高。這種情況是存在的,但要求也高,比如字節(jié),華為,騰訊,阿里等確實(shí)能給到這么高的薪資,但學(xué)歷基本上都是211,985以上,有的還要求是碩士。在中國(guó)211和985錄取的比例加起來還不到5%,大部分人是拿不到這么高的薪資的。雙非院校的程序員本科畢業(yè)月薪十幾k不算少(除非有能力進(jìn)入大廠),所以不要被那行大廠的薪資給迷惑了。 --------------下面是今天的算法題-------------- 來看下今天的算法題,這題是LeetCode的第236題:二叉樹的最近公共祖先。 給定一個(gè)二叉樹, 找到該樹中兩個(gè)指定節(jié)點(diǎn)的最近公共祖先。最近公共祖先的定義為:“對(duì)于有根樹 T 的兩個(gè)節(jié)點(diǎn) p、q,最近公共祖先表示為一個(gè)節(jié)點(diǎn) x,滿足 x 是 p、q 的祖先且 x 的深度盡可能大(一個(gè)節(jié)點(diǎn)也可以是它自己的祖先)。”輸入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 1 輸出:3 解釋:節(jié)點(diǎn) 5 和節(jié)點(diǎn) 1 的最近公共祖先是節(jié)點(diǎn) 3 。
輸入:root = [3,5,1,6,2,0,8,null,null,7,4], p = 5, q = 4 輸出:5 解釋:節(jié)點(diǎn) 5 和節(jié)點(diǎn) 4 的最近公共祖先是節(jié)點(diǎn) 5 。因?yàn)楦鶕?jù)定義最近公共祖先節(jié)點(diǎn)可以為節(jié)點(diǎn)本身。 這題讓找出兩個(gè)節(jié)點(diǎn)的最近公共節(jié)點(diǎn),有兩種解決方式,一種是從兩個(gè)要查找的節(jié)點(diǎn)到根節(jié)點(diǎn)上的路徑都連接起來,那么這兩條路徑就相當(dāng)于兩個(gè)鏈表了,這題就變成了查找兩個(gè)鏈表的第一個(gè)公共節(jié)點(diǎn)了。怎么連接呢?我們可以遍歷這棵二叉樹,然后使用一個(gè)map記錄所遍歷節(jié)點(diǎn)的父節(jié)點(diǎn),然后在根據(jù)當(dāng)前節(jié)點(diǎn)一直往上查找父節(jié)點(diǎn),一直到根節(jié)點(diǎn),這種方式比較簡(jiǎn)單,我們?cè)賮砜戳硪环N方式。查找兩個(gè)節(jié)點(diǎn)的最近公共節(jié)點(diǎn),也就是從下往上找,我們知道二叉樹都是從上往下遍歷的,沒法從下往上遍歷。也就是說如果知道一個(gè)節(jié)點(diǎn),肯定能找到它的子節(jié)點(diǎn),但是我們沒法找到它的父節(jié)點(diǎn)。我們這里再來回顧一下遞歸,對(duì)于一棵二叉樹來說因?yàn)槭菑母?jié)點(diǎn)開始的,當(dāng)遞歸往回走的時(shí)候不就是相當(dāng)于從下往上遍歷嗎,所以這題我們可以參考二叉樹的后序遍歷來寫。1,如果兩個(gè)節(jié)點(diǎn)都在左子樹上,就返回左子樹上的結(jié)果。2,如果兩個(gè)節(jié)點(diǎn)都在右子樹上,就返回右子樹上的結(jié)果。3,如果兩個(gè)節(jié)點(diǎn)分別在兩棵子樹上,說明當(dāng)前節(jié)點(diǎn)就是它倆的最近公共祖先節(jié)點(diǎn),直接返回當(dāng)前節(jié)點(diǎn)即可。public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { if (root == null || p == root || q == root) return root; // 參考二叉樹的后序遍歷 TreeNode left = lowestCommonAncestor(root.left, p, q); TreeNode right = lowestCommonAncestor(root.right, p, q); if (left == null)// 左子樹為空,肯定都在右子樹上 return right; if (right == null)// 右子樹為空,肯定都在左子樹上 return left; // 左右子樹都不為空,一個(gè)在左子樹一個(gè)在右子樹,所以root就是他們的最近公共祖先節(jié)點(diǎn)。 return root; }
public: TreeNode *lowestCommonAncestor(TreeNode *root, TreeNode *p, TreeNode *q) { if (root == nullptr || p == root || q == root) return root; // 參考二叉樹的后序遍歷 TreeNode *left = lowestCommonAncestor(root->left, p, q); TreeNode *right = lowestCommonAncestor(root->right, p, q); if (left == nullptr)// 左子樹為空,肯定都在右子樹上 return right; if (right == nullptr)// 右子樹為空,肯定都在左子樹上 return left; // 左右子樹都不為空,一個(gè)在左子樹一個(gè)在右子樹,所以root就是他們的最近公共祖先節(jié)點(diǎn)。 return root; }
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': if root is None or p == root or q == root: return root # 參考二叉樹的后序遍歷 left = self.lowestCommonAncestor(root.left, p, q) right = self.lowestCommonAncestor(root.right, p, q) if left is None: # 左子樹為空,肯定都在右子樹上 return right if right is None: # 右子樹為空,肯定都在左子樹上 return left # 左右子樹都不為空,一個(gè)在左子樹一個(gè)在右子樹,所以root就是他們的最近公共祖先節(jié)點(diǎn)。 return root
博哥,真名:王一博,畢業(yè)十多年,《算法秘籍》作者,專注于數(shù)據(jù)結(jié)構(gòu)和算法的講解,在全球30多個(gè)算法網(wǎng)站中累計(jì)做題2000多道,在公眾號(hào)中寫算法題解800多題,對(duì)算法題有自己獨(dú)特的解題思路和解題技巧,喜歡的可以給個(gè)關(guān)注,也可以下載我整理的1000多頁(yè)的PDF算法文檔。
|