1、問題分析
本質上就是一個二叉樹的遍歷問題,但是需要注意的是根節點要比左子節點都大,而且比右子節點都小,有一個不滿足就失敗。
2、問題解決
筆者以C++方式解決。
#include "iostream"
using namespace std;
#include "algorithm"
#include "vector"
#include "math.h"
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {
}
};
class Solution {
public:
bool isValidBST(TreeNode *root) {
// 如果根節點爲空,則直接返回true
if (root == NULL) {
return true;
}
// 和左子樹比較,如果左子樹有節點比根節點大,則直接返回false
if (!compareWithLeftTree(root->left, root->val)) {
return false;
}
// 和右子樹比較,如果右子樹有節點比根節點小,則直接返回false
if (!compareWithRightTree(root->right, root->val)) {
return false;
}
// 如果根節點符合條件,則遍歷左子節點和右子節點
return isValidBST(root->left) && isValidBST(root->right);
}
/**
* 判斷左子樹是否比全部比根節點小(本質上就是二叉樹的遍歷,這裏使用的是先序遍歷)
* @param root
* @param val
* @return
*/
bool compareWithLeftTree(TreeNode *root, int val) {
// 如果根節點爲空,則直接返回true
if (root == NULL) {
return true;
}
// 如果該節點的值大於根節點,直接返回false
if (root->val >= val) {
return false;
}
// 遞歸遍歷左子節點
if (!compareWithLeftTree(root->left, val)) return false;
// 遞歸遍歷右子節點
return compareWithLeftTree(root->right, val);
}
/**
* 判斷右子樹是否比都比根節點大(這裏的邏輯和左子樹的相反,但是思想類似)
* @param root
* @param val
* @return
*/
bool compareWithRightTree(TreeNode *root, int val) {
// 如果根節點爲空,則直接返回true
if (root == NULL) {
return true;
}
// 如果該節點的值小於根節點,直接返回false
if (root->val <= val) {
return false;
}
// 遞歸遍歷左子節點
if (!compareWithRightTree(root->left, val)) return false;
// 遞歸遍歷右子節點
return compareWithRightTree(root->right, val);
}
};
/**
* 先序遍歷
* @param root
*/
void preorder(TreeNode *root) {
if (root == NULL || root->val == -1) {
return;
}
// 先訪問根節點
cout << root->val << endl;
// 再訪問左子節點
preorder(root->left);
// 最後訪問右子節點
preorder(root->right);
}
/**
* 根據數組創建二叉樹
* @param a
* @param n
* @return
*/
TreeNode *create(int a[], int n) {
// 根據數組大小分配內存空間
TreeNode *ptree = (TreeNode *)malloc(sizeof(TreeNode) * n);
int i;
// 根據數組的值,依次給二叉樹節點賦值
for (i = 0; i < n; i++) {
// if (a[i] == -1) {
// ptree[i] = NULL;
// continue;
// }
ptree[i].val = a[i];//數組a只起到一個賦值的作用
ptree[i].left = NULL;
ptree[i].right = NULL;
}
// 將數組中節點按照二叉樹規則連接起來
for (i = 0; i <= n / 2 - 1; i++)//原來的父親節點範圍爲1~n/2,現在0~n/2-1,所以注意n/2要取到等
{
if (2 * i + 1 <= n - 1)
ptree[i].left = &ptree[2 * i + 1];//把第2*i+1個結點的地址賦給左孩子
if (2 * i + 2 <= n - 1)
ptree[i].right = &ptree[2 * i + 2];
}
return ptree;
}
template<class T>
/**
* 獲取數組長度
* @tparam T
* @param array
* @return
*/
int getsize(T &array) {
return sizeof(array) / sizeof(array[0]);
}
int main() {
// int a[] = {5, 1, 4, -1, -1, 3, 6};
// int a[] = {2,1,3};
int a[] = { 10, 5, 15, -1, -1, 6, 20 };
// 創建二叉樹
TreeNode *pNode = create(a, getsize(a));
// preorder(pNode);
Solution *pSolution = new Solution;
bool b = pSolution->isValidBST(pNode);
cout << b << endl;
system("pause");
return 0;
}
運行結果
有點菜,有時間再優化一下。
3、總結
書上的代碼直接運行絕大部分是對的,但是總有一些軟件的更新使得作者無能爲力。之前的API是對的,但是之後就廢棄了或修改了是常有的事。所以我們需要跟蹤源代碼。這只是一個小小的問題,如果沒有前輩的無私奉獻,很難想象我們自己一天能學到多少內容。感謝各位前輩的辛勤付出,讓我們少走了很多的彎路!
點個贊再走唄!歡迎留言哦!