力扣刷題筆記(9)

emmm,不刷樹的題目還真以爲自己有多瞭解樹。。。題目一做,方紙上得來終覺淺啊,才知道自己的淺薄和學海的浩瀚。

那,我們來看看這次遇到些什麼問題

前情概要

在做樹相關題目時,我覺得基礎還是要先牢靠一點的:
二叉樹的前中後序遍歷


題目(1):探尋樹的深度

給定一個二叉樹,找出其最大深度。

二叉樹的深度爲根節點到最遠葉子節點的最長路徑上的節點數。

說明: 葉子節點是指沒有子節點的節點。

示例:
給定二叉樹 [3,9,20,null,null,15,7],

    3
   / \
  9  20
    /  \
   15   7

返回它的最大深度 3 。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/maximum-depth-of-binary-tree
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。


題目(2):驗證二叉搜索樹

給定一個二叉樹,判斷其是否是一個有效的二叉搜索樹。

假設一個二叉搜索樹具有如下特徵:

節點的左子樹只包含小於當前節點的數。
節點的右子樹只包含大於當前節點的數。
所有左子樹和右子樹自身必須也是二叉搜索樹。
示例 1:

輸入:
    2
   / \
  1   3
輸出: true

示例 2:

輸入:
    5
   / \
  1   4
     / \
    3   6
輸出: false

解釋: 輸入爲: [5,1,4,null,null,3,6]。
根節點的值爲 5 ,但是其右子節點值爲 4 。

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/validate-binary-search-tree
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。


題目(3):驗證對稱樹

給定一個二叉樹,檢查它是否是鏡像對稱的。

例如,二叉樹 [1,2,2,3,4,4,3] 是對稱的。

    1
   / \
  2   2
 / \ / \
3  4 4  3

但是下面這個 [1,2,2,null,3,null,3] 則不是鏡像對稱的:

  1
   / \
  2   2
   \   \
   3    3

進階:

你可以運用遞歸和迭代兩種方法解決這個問題嗎?

來源:力扣(LeetCode) 鏈接:https://leetcode-cn.com/problems/symmetric-tree
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。


我的題解(1)

這題實在簡單的不想說什麼了,連流程圖我都不想畫,直接上代碼吧。

int maxDepth(TreeNode* root) {
        if(root == NULL)
            return 0;
        return 1 + max(maxDepth(root->left), maxDepth(root->right));
    }

簡單吧,三行代碼的事情。。。
或者說,一行代碼的事情而已。。。


我的題解(2)

這題真的打破了我對樹的幻想。我一直以爲二叉搜索樹我還挺熟的,沒想到,居然處處碰壁。。。

剛開始我採用層序遍歷的方式,一層層比對,(當前節點小於當前右節點,大於左節點),但是很快就發現問題了。

在這裏插入圖片描述

如果覺得上面的那個方式沒錯,那麼看完這張圖就不會這麼想了吧。

當時看到這個情況,我也是整個人都不好了,不僅僅要和子節點比對,孫子節點還要防着。。。

經過一早上的掙扎,我放棄了前序遍歷,果然是我基礎不牢,這個模型其實可以用中序遍歷來弄,可惜我就浪費了幾個小時沒想到。

對一顆正常的二叉搜索樹,用中序遍歷打印出來的節點順序是嚴格從一端到另一端的。

當時也想着直接取值比對,但終究是遞歸也不太熟,最後只好把值都放到數組裏在遍歷數組比對了。

struct TreeNode {
	int val;
	TreeNode* left;
	TreeNode* right;
	TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

bool MidOrderTraverse(TreeNode* T, vector<int>& temp)
{
	if (T == NULL)
		return true;

	MidOrderTraverse(T->left,temp);	

	temp.push_back(T->val);
	cout << T->val << " ";
	MidOrderTraverse(T->right,temp);	

	for (int i = 0; i < temp.size()-1; i++)
	{
		int j = i + 1;
		if (temp[i] >= temp[j])
			return false;
	}
	return true;
}

bool isValidBST(TreeNode* T)
{
	vector<int> temp;
	int k = MidOrderTraverse(T, temp);
	return k;
}

最後就做成這個樣子了。


我的題解(3)

經過第二題,我對遞歸又深入瞭解了一點,知道該把一些希望固定住的值固定住,可以用參數形式,也可以用static.

那這題其實就很簡單了,只要把樹從根節點左右對半開,然後比較左右兩顆子樹就好,比較子樹的話,前中後序都可以,不過需要做一點小改變:

我用的是正反前序遍歷同步的方法

int Pre(TreeNode* Tl, TreeNode* Tr,int flag)	//flag爲標誌退出循環
{
	if (flag == 0)
		return false;

	if (Tl == NULL)
	{
		if(Tr == NULL)
			return true;
		return false;
	}
	if (Tr == NULL)
		return false;
		
	if (Tl->val != Tr->val)
	{
		flag = 0;
		return false;
	}
	
	flag = Pre(Tl->left,Tr->right,flag);
	if (flag == 0)
		return false;

	flag = Pre(Tl->right,Tr->left,flag);
	if (flag == 0)
		return false;
	return true;
}

bool isSymmetric(TreeNode* root)
{

	//先排除極端情況
	if (root == NULL)
		return true;
	if (root->left == NULL)
	{
		if (root->right != NULL)
			return false;
		return true;
	}
	if (root->right == NULL)
		return false;

	if (root->left->val != root->right->val)
		return false;

	int ret = Pre(root->left, root->right,1);

	return ret;
}

看着挺多的,其實四分之三的篇幅都用在了對特殊情況的剔除上。真正匹配的代碼是這裏:

int Pre(TreeNode* Tl, TreeNode* Tr,int flag)	//flag爲標誌退出循環
{
	if (flag == 0)
		return false;

	flag = Pre(Tl->left,Tr->right,flag);
	if (flag == 0)
		return false;

	flag = Pre(Tl->right,Tr->left,flag);
	if (flag == 0)
		return false;
	return true;
}

官方題解(1)略

官方題解(2)

方法一: 遞歸

上述思路可以用遞歸法實現。首先將結點的值與上界和下界(如果有)比較。然後,對左子樹和右子樹遞歸進行該過程。

在這裏插入圖片描述

class Solution {
  public boolean helper(TreeNode node, Integer lower, Integer upper) {
    if (node == null) return true;

    int val = node.val;
    if (lower != null && val <= lower) return false;
    if (upper != null && val >= upper) return false;

    if (! helper(node.right, val, upper)) return false;
    if (! helper(node.left, lower, val)) return false;
    return true;
  }

  public boolean isValidBST(TreeNode root) {
    return helper(root, null, null);
  }
}

> 作者:LeetCode
> 鏈接:https://leetcode-cn.com/problems/validate-binary-search-tree/solution/yan-zheng-er-cha-sou-suo-shu-by-leetcode/ 來源:力扣(LeetCode) 著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

複雜度分析

時間複雜度 : O(N)。每個結點訪問一次。
空間複雜度 : O(N)。我們跟進了整棵樹。


官方題解(3)

和我的差不多,迭代的就不說了。


總結

樹!!!
我也不多說,心照不宣

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章