✏️Leetcode經典二叉樹題目集合
開題:這位同志,麻煩你手寫一個紅黑樹出來......告辭!!!!!
✏️1.二叉樹的前序遍歷(leetcode144)
前序遍歷,先訪問根結點,然後在訪問左子樹,最後訪問右子樹。可以利用棧的特點,這裡我結合了佇列和棧的特點來實現。先壓入樹,取出根節點。先把根節點值push到佇列中,然後把右子樹壓入棧中,最後壓入左子樹。返回佇列。當然你可以調整成你想要的實現方式。(只要前中後序順序理解正確即可)
/**
* Definition for a binary tree node.
* class TreeNode {
* public $val = null;
* public $left = null;
* public $right = null;
* function __construct($value) { $this->val = $value; }
* }
*/
class Solution {
/**
* @param TreeNode $root
* [@return](https://learnku.com/users/31554) Integer[]
*/
function preorderTraversal($root) {
$res=[];
$list=[];
array_unshift($res,$root);
while(!empty($res)){
$current=array_shift($res);
if($current==null) continue;
array_push($list,$current->val);
array_unshift($res,$current->right);
array_unshift($res,$current->left);
}
return $list;
}
}
✏️2.二叉樹的中序遍歷(leetcode94)
/**
* @param TreeNode $root
* @return Integer[]
*/
function inorderTraversal($root) {
$res=[];
$this->helper($root,$res);
return $res;
}
function helper($root,&$res){
if($root !=null){
if($root->left !=null) $this->helper($root->left,$res);
array_push($res,$root->val);
if($root->right !=null) $this->helper($root->right,$res);
}
}
或者不用遞迴
/**
* @param TreeNode $root
* @return Integer[]
*/
function inorderTraversal($root) {
$res=[];
$list=[];
while(!empty($list) || $root !=null){
while($root != null){
array_unshift($list,$root);
$root=$root->left;
}
$root=array_shift($list);
array_push($res,$root->val);
$root=$root->right;
}
return $res;
}
✏️3.二叉樹的後序遍歷(leetcode145)
/**
* @param TreeNode $root
* @return Integer[]
*/
function postorderTraversal($root) {
$list=[];
$res=[];
array_push($list,$root);
while(!empty($list)){
$node=array_shift($list);
if(!$node) continue;
array_unshift($res,$node->val);
array_unshift($list,$node->left);
array_unshift($list,$node->right);
}
return $res;
}
}
✏️4.二叉樹的層次遍歷(leetcode102)
DFS和BFS都可以解,竟然已經要我們按照層列印了,那麼先使用BFS,思路就是先判斷樹是否是空,不是空加入一個佇列的結構中,如果佇列不為空,取出頭元素,那麼當前元素表示的就是當前這一層了,所以只需要遍歷這一層裡的所有的元素即可,然後下一層....
class Solution {
/**
* @param TreeNode $root
* @return Integer[][]
*/
function levelOrder($root) {
if(empty($root)) return [];
$result = [];
$queue = [];
array_push($queue,$root);
while(!empty($queue)){
$count = count($queue);
$leveQueue = [];
for($i = 0;$i<$count;$i++){
$node = array_shift($queue);
array_push($leveQueue,$node->val);
if($node->left) array_push($queue,$node->left);
if($node->right) array_push($queue,$node->right);
}
array_push($result,$leveQueue);
}
return $result;
}
}
如果使用DFS的話,就是一條路走到黑,然後再重新一路路的退回來再找下一路,所以這樣的話,每一次我們需要記錄一下當前他所在的這個點屬於哪一層即可,程式碼用遞迴實現。
class Solution {
/**
* @param TreeNode $root
* @return Integer[][]
*/
function levelOrder($root) {
if(empty($root)) return [];
$result=[];
$this->helper($result,$root,0);
return $result;
}
function helper(&$result,$node,$level){
if(empty($node)) return ;
if(count($result)<$level+1){
array_push($result,[]); //說明當前行沒有結果
}
array_push($result[$level],$node->val);
$this->helper($result,$node->left,$level+1);
$this->helper($result,$node->right,$level+1);
}
}
✏️5.二叉樹的最大深度(leetcode104)
DFS和BFS都可以解,竟然已經要我們按照層列印了,那麼先使用BFS,思路就是先判斷樹是否是空,不是空加入一個佇列的結構中,如果佇列不為空,取出頭元素,那麼當前元素表示的就是當前這一層了,所以只需要遍歷這一層裡的所有的元素即可,然後下一層....
/**
* @param TreeNode $root
* @return Integer
*/
function maxDepth($root) {
if(empty($root)) return 0;
$left = $this->maxDepth($root->left);
$right = $this->maxDepth($root->right);
return $left<$right? $right+1:$left+1;
return max($left,$right)+1;
}
✏️6.二叉樹的最小深度(leetcode111)
DFS和BFS都可以求解
//BFS
/**
* @param TreeNode $root
* @return Integer
*/
function minDepth($root) {
if(empty($root)) return 0;
if(!$root->right) return $this->minDepth($root->left)+1;
if(!$root->left) return $this->minDepth($root->right)+1;
$left=$this->minDepth($root->left);
$right=$this->minDepth($root->right);
return min($left,$right)+1;
}
//DFS
/**
* @param TreeNode $root
* @return Integer
*/
function minDepth($root) {
if(empty($root)) return 0;
$left=$this->minDepth($root->left);
$right=$this->minDepth($root->right);
if($left==0 || $right==0) return $left+$right+1;
return min($left,$right)+1;
}
✏️7.判斷是否是平衡二叉樹(leetcode110)
每一節點的兩個子樹的深度相差不能超過1。如果是空樹,直接true。
class Solution {
/**
* @param TreeNode $root
* @return Boolean
*/
private $result=true;
function isBalanced($root) {
if(empty($root)) return true;
$this->helper($root);
return $this->result;
}
function helper($root)
{
if(!$root) return ;
$left=$this->helper($root->left);
$right=$this->helper($root->right);
if(abs($left-$right)>1) $this->result=false;
return max($left,$right)+1;
}
}
✏️8.判斷是否是對稱二叉樹(leetcode101)
1.兩個子節點都是空,那說明他們是對稱的返回true
2.一個子節點為空,另一個子節點不為空,false
3.兩個子節點都不為空,但是他們不相等,false
4.兩個子節點不為空且相等,繼續判斷他們的左子樹和右子樹,把左子樹的左子節點和右子樹的右子節點進行比較,把左子樹的右子節點和右子樹的左子節點進行比較
/**
* @param TreeNode $root
* @return Boolean
*/
function isSymmetric($root) {
if(empty($root)) return true;
return $this->helper($root->left,$root->right);
}
function helper($l,$r){
if(!$l && !$r) return true;
if(!$l || !$r || $l->val != $r->val) return false;
return $this->helper($l->left ,$r->right) && $this->helper($l->right,$r->left);
}
✏️9.反轉二叉樹(leetcode226)
/**
* @param TreeNode $root
* @return TreeNode
*/
function invertTree($root) {
if(!$root) return null;
$list=[];
array_push($list,$root);
while(!empty($list)){
$node=array_shift($list);
$temp=$node->left;
$node->left=$node->right;
$node->right=$temp;
if($node->left) array_push($list,$node->left);
if($node->right) array_push($list,$node->right);
}
return $root;
}
遞迴解
/**
* @param TreeNode $root
* @return TreeNode
*/
function invertTree($root) {
if(empty($root)){
return null;
}
$right=$this->invertTree($root->right);
$left=$this->invertTree($root->left);
$root->left=$right;
$root->right=$left;
return $root;
}
✏️10.給定單連結串列(值有序)轉化成平衡二叉查詢樹(leetcode109)
先將連結串列資料轉換成有序陣列,然後利用二分查詢的特性,構建左右子樹。
/**
* Definition for a singly-linked list.
* class ListNode {
* public $val = 0;
* public $next = null;
* function __construct($val) { $this->val = $val; }
* }
*/
/**
* Definition for a binary tree node.
* class TreeNode {
* public $val = null;
* public $left = null;
* public $right = null;
* function __construct($value) { $this->val = $value; }
* }
*/
class Solution {
/**
* @param ListNode $head
* @return TreeNode
*/
function sortedListToBST($head) {
$data=[];
while($head){
array_push($data,$head->val);
$head=$head->next;
}
return $this->helper($data);
}
function helper($data)
{
if(!$data) return ;
$middle=floor(count($data)/2);
$node=new TreeNode($data[$middle]);
$node->left=$this->helper(array_slice($data,0,$middle));
$node->right=$this->helper(array_slice($data,$middle+1));
return $node;
}
}
✏️11.強盜打劫版本3(leetcode337)
最後的目的算出最多能搶金額數而不觸發報警器。除了根節點,每一個結點只有一個父節點,能直接相連的兩個節點不能同時搶,比如圖1,搶了根節點,直接相連的左右子結點就不能搶。所以要麼搶根節點的左右子結點,要麼根結點+根結點->left->right+根結點->right->right。
//遞迴
/**
* @param TreeNode $root
* @return Integer
*/
function rob($root) {
if($root==null){
return 0;
}
$res1=$root->val;
if($root->left !=null) {
$res1 +=$this->rob($root->left->left)+$this->rob($root->left->right);
}
if($root->right !=null){
$res1 +=$this->rob($root->right->left)+$this->rob($root->right->right);
}
$res2=$this->rob($root->left)+$this->rob($root->right);
return max($res1,$res2);
}
上面那種大量的重複計算,改進一下。
如果結點不存在直接返回0,對左右結點分別遞迴,設定了4個變數,ll和lr分別表示左子結點的左右子結點的最大金額數,rl和rr分別表示右子結點的左右子結點的最大金額數。所以我們最後比較的還是兩種情況,第一種就是當前結點+左右子結點的左右子結點的值(即這裡定義的ll,lr,rl,rr).第二種是當前結點的左右子結點的值(也就是說我只搶當前結點的子結點,不搶當前結點和孫子結點),再通俗的說就是如果樹的層數是3層,要麼搶中間一層,要麼搶上下兩層,誰錢多搶誰。
/**
* @param TreeNode $root
* @return Integer
*/
function rob($root) {
$l=0;$r=0;
return $this->countMax($root,$l,$r);
}
function countMax($root,&$l,&$r){
if($root==null) return 0;
$ll=0;$lr=0;$rl=0;$rr=0;
$l=$this->countMax($root->left,$ll,$lr);
$r=$this->countMax($root->right,$rl,$rr);
return max($root->val+$ll+$lr+$rl+$rr,$l+$r);
}
✏️12.判斷二叉樹路徑和是否存在(leetcode112)
只要使用深度優先演算法思想遍歷每一條完整的路徑,如果是個空樹直接false,如果結點沒有左右子樹(說明此時已然是葉子結點,判斷值是否是給定值,這個條件正好是遞迴終止的條件),相等直接返回true,根據這個推匯出遞迴公式。
/**
* @param TreeNode $root
* @param Integer $sum
* @return Boolean
*/
function hasPathSum($root, $sum) {
if($root==null){
return false;
}
if($root->left ==null && $root->right==null && $root->val==$sum) return true;
return $this->hasPathSum($root->left,$sum-$root->val) || $this->hasPathSum($root->right,$sum-$root->val);
}
改成迭代
/**
* @param TreeNode $root
* @param Integer $sum
* @return Boolean
*/
function hasPathSum($root, $sum) {
if($root==null){
return false;
}
$res=[];
array_push($res,$root);
while(!empty($res)){
$node=array_shift($res);
if(!$node->left && !$node->right ){
if($node->val==$sum) return true;
}
if($node->left){
$node->left->val +=$node->val;
array_push($res,$node->left);
}
if($node->right){
$node->right->val +=$node->val;
array_push($res,$node->right);
}
}
return false;
}
✏️13.判斷是否是二叉查詢樹(leetcode98)
思路有兩種,二叉查詢樹的特點就是左子樹上的結點都小於根結點,右子樹上的結點都大於根節點。所以有兩個方向,可以分別遞迴的判斷左子樹,右子樹。或者拿左子樹上的最大值,右子樹上的最小值分別對應根結點進行判斷。
/**
* Definition for a binary tree node.
* class TreeNode {
* public $val = null;
* public $left = null;
* public $right = null;
* function __construct($value) { $this->val = $value; }
* }
*/
class Solution {
/**
* @param TreeNode $root
* @return Boolean
*/
function isValidBST($root) {
return $this->helper($root,null,null);
}
function helper($root,$lower,$upper){
if($root==null) return true;
$res=$root->val;
if($lower !==null && $res<=$lower) return false;
if($upper !==null && $res>=$upper) return false;
if(!$this->helper($root->left,$lower,$res)) return false;
if(!$this->helper($root->right,$res,$upper)) return false;
return true;
}
}
✏️14.找出二叉樹最後一層最左邊的值(leetcode513)
思路有兩種,二叉查詢樹的特點就是左子樹上的結點都小於根結點,右子樹上的結點都大於根節點。所以有兩個方向,可以分別遞迴的判斷左子樹,右子樹。或者拿左子樹上的最大值,右子樹上的最小值分別對應根結點進行判斷。
/**
* @param TreeNode $root
* @return Integer
*/
function findBottomLeftValue($root) {
$data=[];
array_push($data,$root);
while(!empty($data)){
$node = array_shift($data);
if($node->right) array_push($data,$node->right);
if($node->left) array_push($data,$node->left);
}
return $node->val;
}
Github整理地址:https://github.com/wuqinqiang/leetcode-php 如果對你有幫助歡迎star