AVL-平衡二叉搜尋樹(Self-balancing binary search tree)
======================= **基礎知識** =======================
二叉排序樹(二叉搜尋樹):思維結構中可以是有序陣列,樹;
性質: 左子樹 < 根節點 ; 右子樹 > 根節點;
中序遍歷結果:就是遞增排序的有序序列;(3,17, 20, 28, 28, 29, 30, 32)
操作:
增(插入): 與根結點比較:小於:進入左子樹;大於:進入右子樹;重複操作,直到找到一個空節點插入該數;
查:與根節點比較,小於進入左子樹,大於進入右子樹,直到找到該數;
刪:對應多種情況,分類處理;
1.刪除葉子節點:直接刪除;
2.刪除度為1 的節點: 只要存在上一個根節點,直接將孩子頂替當前被刪除的節點;
3. 刪除度為2 的節點: 前驅節點 :相對刪除節點,左子樹中離他最近的節點(左子樹一直往右),左子樹中最大值;
後置節點: 相對刪除節點,右子樹中離他最近的節點(右子樹一直往左),右子樹中最小值;
對於前驅/後置節點:它們最多為度為1 的節點;如果度為2 ,一定存在左右子樹,那就不會是當前子樹中最值;
所以就可以把前驅(後置)節點替換刪除節點,然後將問題轉換為刪除度為1/0 的操作;
缺點: 二叉排序樹,有可能退化成如下的連結串列,使得所有的操作時間複雜度變成O(n);
用途: 用於解決排名相關的檢索需求;
AVL 樹:平衡二叉排序樹:重點在於平衡條件!!
AVL樹得名於它的發明者G. M. Adelson-Velsky和E. M. Landis,他們在1962年的論文《An algorithm for the organization of information》中發表了它。
性質:除了上面的二叉排序樹的性質以外: | H(left) - H(right) | <= 1; 左右子樹的高度差不超過1;
優點:
基本操作:
左旋: 以k1 為基點,將k3 點左旋上來;A 節點變成K1 的右子樹;
右旋: 左旋的反向操作:
左/右旋操作後,仍然保證了二叉排序的性質;
在增刪改查操作中,只有增/刪 會有可能引起AVL 樹失衡;
在增/刪 以後的遞歸回溯過程中,在當前節點向下看,如果AVL 樹失衡,為了維護AVL 樹的性質,就需要進行調整;調整可能會進行多次;
經典的AVL 樹 -失衡型別: 主要3大類: LL/RR型,LR型,RL 型;注意:刪除/插入操作,每次只會增加(減少)一個節點,而原樹也是AVL 樹,這也是下面公式推導中要注意的點;
LL/RR 型: 在K1節點向下看, 左子樹K2節點高(L); 在K2節點中,左子樹A節點高(L);
解決方案:LL : 抓住K1 大右旋,將K2 旋轉上來; RR: 直接抓住K1 大左旋;
LL型: RR型
LR 型: 在K1節點向下看, 左子樹K2節點高(L); 在K2節點中,左子樹K3節點高(R);
解決方案: 先抓K2左旋,變成LL 型; 然後再抓K1 右旋;
RL 型: 與LR 型相反;
解決方案: 與LR 型相反,先小右旋,變成RR型; 再大左旋;
對於LR/RL 型別旋轉的過程:
LR型: RL型:
======================= **程式碼演示** =======================
資料結構是定義一種性質,並維護這種性質;
1. 實現二叉排序樹:程式碼中注意對於erase 的刪除部分的處理,尤其是對於度為2 節點的刪除;插入/刪除過程返回更新後的節點;
1 //#include "binaryTree.h" 2 #include <iostream> 3 using namespace std; 4 5 struct Node{ 6 Node(int key = 0, Node *left = nullptr, Node *right = nullptr) 7 : key(key), left(left), right(right) {} 8 int key; 9 Node *left, *right; 10 11 }; 12 13 Node *getNewnode(int key) { 14 return new Node(key); 15 } 16 17 Node *insert(Node *root, int key){ //返回插入新節點以後的root 地址 18 if(root == nullptr) return getNewnode(key); 19 if(root->key == key) return root; 20 21 if(key < root->key) root->left = insert(root->left,key); //這裡就用到返回值,減少操作,多體會 22 if(key > root->key) root->right = insert(root->right,key); 23 return root; 24 } 25 26 Node *predeccessor(Node *root) { //左子樹最大值 27 Node *temp = root->left; 28 while(temp->right) temp = temp->right; 29 return temp; 30 } 31 32 Node *erase(Node *root, int key) { 33 if(root == nullptr) return root; 34 if(key < root->key) root->left = erase(root->left, key); 35 else if(key > root->key) root->right = erase(root->right, key); 36 else { 37 // if(root->left == nullptr && root->right == nullptr){ //度為0 38 // delete root; 39 // return nullptr; 40 if( root->left == nullptr || root->right == nullptr){//度為1 41 Node *temp = root->left ? root->left : root->right; 42 delete root; 43 return temp; 44 } else { 45 Node *temp = predeccessor(root); 46 root->key = temp->key; 47 root->left = erase(root->left, temp->key); 48 } 49 } 50 return root; 51 } 52 53 void clear(Node *root) { 54 if(root == nullptr) return; 55 clear(root->left); 56 clear(root->right); 57 delete root; 58 return; 59 } 60 61 void output(Node *root) { 62 if(!root) return; 63 output(root->left); 64 cout << root->key << " "; 65 output(root->right); 66 return; 67 } 68 69 int main() 70 { 71 int op, val; 72 Node *root = nullptr; 73 while(cin >> op >> val) { 74 switch (op) { 75 case 0 : root = insert(root, val); break; 76 case 1 : root = erase(root, val); break; 77 } 78 output(root); 79 cout << endl; 80 } 81 return 0; 82 }面向過程實現二叉搜尋樹
1 //input : 2 //0 3 3 //0 2 4 //0 1 5 //0 5 6 //0 4 7 //1 3 8 //1 4 9 10 #include <iostream> 11 using namespace std; 12 13 struct Node { 14 Node(int v = -1, Node *l = nullptr, Node *r = nullptr) : val(v), left(l), right(r){} 15 Node *left, *right; 16 int val; 17 }; 18 19 class BinaryTree{ 20 private: 21 Node *root; 22 void clear(Node *root){ 23 if(!root) return; 24 if(root->left) clear(root->left); 25 if(root->right) clear(root->right); 26 delete root; 27 return; 28 } 29 30 Node *__insert(Node* r, int key) { 31 if(!r) return new Node(key); 32 if(key < r->val) r->left = __insert(r->left, key); 33 else if(key > r->val) r->right = __insert(r->right, key); 34 return r; 35 } 36 37 Node *__find(Node *r, int key) { 38 if(!r) return nullptr; 39 if(key < r->val) return __find(r->left, key); 40 else if(key > r->val) return __find(r->right, key); 41 return r; 42 } 43 44 Node *predeccessor(Node *r) { //後驅節點 45 Node *temp = r->right; 46 while(temp->left) temp = temp->left; 47 return temp; 48 } 49 50 Node *__erase(Node *r, int key) { 51 if(!r) return nullptr; 52 53 if(key < r->val) r->left = __erase(r->left , key); 54 else if(key > r->val) r->right = __erase(r->right, key); 55 else { 56 if(!r->left || !r->right) { 57 Node *son = r->left ? r->left : r->right; 58 delete r; 59 return son; 60 } else { 61 Node *__predec = predeccessor(r); 62 r->val = __predec->val; 63 r->right = __erase(r->right, __predec->val); 64 } 65 } 66 return r; 67 } 68 69 void __output(Node *r) { 70 if(!r) return; 71 __output(r->left); 72 cout << r->val << " "; 73 __output(r->right); 74 return; 75 } 76 77 78 public: 79 BinaryTree(Node *pn) = delete; 80 BinaryTree(int key) { 81 root = new Node(key); 82 } 83 //copy/move ... 84 ~BinaryTree() { 85 clear(root); 86 } 87 88 void insert(int key) { 89 root = __insert(root, key); 90 return; 91 } 92 93 void erase(int key){ 94 root = __erase(root, key); 95 return; 96 } 97 98 Node *find(int key){ 99 return __find(root, key); 100 } 101 102 void output() { 103 __output(root); 104 return; 105 } 106 107 }; 108 109 int main() 110 { 111 int op, val; 112 BinaryTree *pbt = nullptr; 113 while(cin >> op >> val) { 114 switch(op) { 115 case 0: { 116 if(!pbt) pbt = new BinaryTree(val); 117 else pbt->insert(val); 118 break; 119 } 120 case 1: { 121 if(pbt) pbt->erase(val); 122 break; 123 } 124 } 125 pbt->output(); 126 cout << endl; 127 } 128 return 0; 129 }面對物件實現二叉排序樹
2. AVL樹 程式碼實現:程式碼中注意點:虛擬空節點的引入,優化程式(虛擬空節點的 程式碼技巧);
對於每個變化的節點都要重新更新深度;左旋/右旋/插入/刪除
以及上面二叉排序樹中的注意點;
1 //input 2 //0 5 3 //0 9 4 //0 8 5 //0 3 6 //0 2 7 //0 4 8 //0 1 9 //0 7 10 //1 8 11 //1 1 12 //1 5 13 14 15 #include <iostream> 16 using namespace std; 17 18 #define NIL (&Node::__NIL) 19 20 struct Node { 21 Node(int k = 0, int h = 0, Node *l = NIL, Node *r = NIL) 22 : key(k), h(h), left(l), right(r) {} 23 int key, h; 24 Node *left, *right; 25 static Node __NIL; //這裡只是宣告 26 }; 27 28 Node Node::__NIL; //對於靜態變數的使用,這裡才是定義 29 30 Node *getNewNode(int key) { 31 return new Node(key,1); 32 } 33 34 void clear(Node *root) { 35 if(root == NIL) return; 36 clear(root->left); 37 clear(root->right); 38 cout << "del root key: " << root->key << endl; 39 delete root; 40 return; 41 } 42 43 void update_height(Node *root) { 44 //NIL if(root->left = nullptr && root->right == nullptr) return; 45 //NIL if(root->left == nullptr) root->h = root->right->h + 1; 46 //NIL else if(root->right == nullptr) root->h = root->left->h + 1; 47 root->h = max(root->left->h, root->right->h) + 1; 48 return; 49 } 50 51 Node *left_rotate(Node *root){ 52 Node *new_root = root->right; 53 root->right = new_root->left; 54 new_root->left = root; 55 update_height(root); 56 update_height(new_root); 57 return new_root; 58 } 59 60 Node *right_rotate(Node *root){ 61 Node *new_root = root->left; 62 root->left= new_root->right; 63 new_root->right= root; 64 update_height(root); 65 update_height(new_root); 66 return new_root; 67 } 68 69 const char *Type[5] = {"", "LL", "RR", "LR", "RL"}; 70 71 Node *maintain(Node *root) { 72 if(abs(root->left->h - root->right->h) < 2) return root; 73 int type = 0; 74 if(root->left->h > root->right->h) { 75 if(root->left->right->h > root->left->left->h) { 76 //lr 77 printf("%d : left rotate\n", root->left->key); 78 type = 3; 79 root->left = left_rotate(root->left); 80 } 81 //ll 82 if(!type) type = 1; 83 printf("%d : right rotate\n", root->key); 84 root = right_rotate(root); 85 }else { 86 if(root->right->left->h > root->right->right->h) { 87 //rl 88 type = 4; 89 printf("%d : right rotate\n", root->right->key); 90 root->right = right_rotate(root->right); 91 } 92 //rr 93 printf("%d : left rotate\n", root->key); 94 if(!type) type = 2; 95 root = left_rotate(root); 96 } 97 printf("maintian the type = %s;\n", Type[type]); 98 return root; 99 } 100 101 Node *insert(Node *root, int key) { 102 if(root == NIL) return getNewNode(key); 103 if(root->key == key) return root; 104 105 if(key < root->key) root->left = insert(root->left, key); 106 else root->right = insert(root->right, key); 107 update_height(root); 108 return maintain(root); 109 } 110 111 Node* predeccesor(Node *root) { 112 Node *temp = root->left; 113 while(temp->right != NIL) temp = temp->right; 114 return temp; 115 } 116 117 Node *erase(Node *root, int key){ 118 if(root == NIL) return root; 119 if(key < root->key) root->left = erase(root->left, key); 120 else if(key > root->key) root->right = erase(root->right, key); 121 else { 122 //刪除節點數為0 或 1 的節點 123 if(root->left == NIL || root->right == NIL) { 124 Node *temp = root->left == NIL ? root->right : root->left; 125 delete root; 126 return temp; 127 }else { //刪除節點數為2 , 這裡使用左子樹最右邊的值替補被刪除的數(也可以通過右子樹最左邊的值替補被刪除的值) 128 Node *temp = predeccesor(root); 129 root->key = temp->key; 130 root->left = erase(root->left, temp->key); 131 } 132 } 133 update_height(root); 134 return maintain(root); 135 } 136 137 void print(Node *root) { 138 printf("(%d[%d] | %d, %d)\n", root->key, root->h, root->left->key, root->right->key); 139 return; 140 } 141 142 void output(Node *root) { 143 if(root == NIL) return; 144 print(root); 145 output(root->left); 146 output(root->right); 147 return; 148 } 149 150 int main() 151 { 152 int op, val; 153 Node *root = NIL; 154 while(cin >> op >> val) { 155 cout << endl << "====AVL tree print ====" << endl; 156 switch (op) { 157 case 0 : { 158 printf("insert %d\n", val); 159 root = insert(root, val); break; 160 } 161 case 1 : { 162 printf("erase the %d\n", val); 163 root = erase(root, val); break; 164 } 165 } 166 output(root); 167 cout << "====tree print end====" << endl; 168 } 169 170 clear(root); 171 172 return 0; 173 }AVL Tree
======================= **經典問題** =======================
1. 前驅/後繼的求取: 面試題 04.06. 後繼者 : 非常好的鍛鍊結構化思維的例題!; 使用pre 記錄前一個節點值,程式碼技巧;
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 TreeNode* pre; 13 TreeNode *inOrder(TreeNode *r, TreeNode *p) { 14 if(!r) return nullptr; 15 TreeNode *ans = nullptr; 16 if(ans = inOrder(r->left, p)) return ans; 17 if(pre && pre == p) return r; 18 pre = r; //精髓 19 return inOrder(r->right, p); 20 } 21 22 TreeNode* inorderSuccessor(TreeNode* root, TreeNode* p) { 23 //利用二叉樹結構化思維方式求解 24 pre = nullptr; 25 return inOrder(root, p); 26 // 利用二叉排序樹性質求解 27 // TreeNode *ans = nullptr; 28 // 29 // if(p->val < root->val) ans = inorderSuccessor(root->left, p); 30 // else if(p->val > root->val) return inorderSuccessor(root->right, p); 31 // else { 32 // if(!root->right) return nullptr; 33 // TreeNode *next = root->right; 34 // while(next->left) next= next->left; 35 // return next; 36 // } 37 // if(!ans) ans = root; 38 // return ans; 39 } 40 };二叉樹結構化思維/二叉排序樹性質:分別求解
2. 450. 刪除二叉搜尋樹中的節點 : BST 刪除節點的裸題:對於不同度的節點處理;
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 * }; 11 */ 12 class Solution { 13 public: 14 TreeNode *predecessor(TreeNode *root){ 15 TreeNode *temp = root->left; 16 while(temp->right) temp = temp->right; 17 return temp; 18 } 19 20 //這題目就是BST 中刪除指定節點操作 21 TreeNode* deleteNode(TreeNode* root, int key) { 22 if(!root) return nullptr; 23 24 if(key < root->val) root->left = deleteNode(root->left, key); 25 else if(key > root->val) root->right = deleteNode(root->right, key); 26 else { 27 //出度為0 或 1 28 if(root->left == nullptr || root->right == nullptr) { 29 TreeNode *temp = root->left ? root->left : root->right; 30 delete root; 31 return temp; 32 } else { 33 //出度為2 34 TreeNode *temp = predecessor(root); 35 root->val = temp->val; 36 root->left = deleteNode(root->left, temp->val); 37 } 38 } 39 return root; 40 } 41 };刪除節點裸題
3.對於樹型別資料,結構化思維是很重要的一種手段;上面的AVL 樹的程式碼實現中也利用了結構化思維來實現;
結構化思維訓練:
501. 二叉搜尋樹中的眾數 : 結構化思維;這裡對於最後節點需要判斷情況下,避免重複程式碼有很好示範;
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 * }; 11 */ 12 //這裡對於減少最後節點判斷過程,做了一個不錯的示範; 13 class Solution { 14 public: 15 int max_cnt, cnt, pre_val; 16 vector<int> ans; 17 18 void __inorder(TreeNode* root) { 19 if(!root) return; 20 __inorder(root->left); 21 22 if(pre_val == root->val) cnt++; 23 else { 24 cnt = 1; 25 pre_val = root->val; 26 } 27 28 //這裡是為了解決最後一個節點,不用單獨寫一份判斷過程; 29 if(cnt == max_cnt) { 30 ans.push_back(pre_val); 31 } else if(cnt > max_cnt) { 32 max_cnt = cnt; 33 ans.clear(); 34 ans.push_back(pre_val); 35 } 36 37 __inorder(root->right); 38 return; 39 } 40 41 vector<int> findMode(TreeNode* root) { 42 pre_val = root->val, //體會這樣做的好處 43 max_cnt = 0, cnt = 0; 44 ans.clear(); 45 46 __inorder(root); 47 return ans; 48 } 49 }; 50 51 52 //original 53 /** 54 * Definition for a binary tree node. 55 * struct TreeNode { 56 * int val; 57 * TreeNode *left; 58 * TreeNode *right; 59 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 60 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 61 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 62 * }; 63 */ 64 class Solution { 65 public: 66 int cnt, max_cnt; 67 TreeNode *pre; 68 69 void findMax(TreeNode *root, vector<int> &ans){ 70 if(!root) return; 71 72 findMax(root->left, ans); 73 if(!pre) cnt = 1; 74 else { 75 if(pre->val == root->val) cnt++; 76 else{ 77 if(cnt >= max_cnt) { 78 if(cnt > max_cnt) ans.clear(), max_cnt = cnt; 79 ans.push_back(pre->val); 80 } 81 cnt = 1; 82 } 83 } 84 pre = root; 85 86 findMax(root->right, ans); 87 return; 88 } 89 90 vector<int> findMode(TreeNode* root) { 91 cnt = max_cnt = 0; 92 pre = nullptr; 93 vector<int> ans; 94 findMax(root, ans); 95 if(cnt < max_cnt) return ans; 96 if(cnt > max_cnt) ans.clear(); 97 ans.push_back(pre->val); 98 return ans; 99 } 100 };結構化思維/最後節點處理,避免重複程式碼示例
1382. 將二叉搜尋樹變平衡 : 二叉排序樹的實現方式也有很多,在樹結構中,很多時候使用結構性思維;
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 * }; 11 */ 12 class Solution { 13 public: 14 void inorder(TreeNode *root, vector<TreeNode*> &nums) { 15 if(!root) return; 16 inorder(root->left, nums); 17 nums.push_back(root); 18 inorder(root->right, nums); 19 return; 20 } 21 22 TreeNode *buildTree(vector<TreeNode*> &nums, int l, int r) { 23 if(l > r) return nullptr; 24 int ind = (l + r) >> 1; 25 TreeNode *node = nums[ind]; 26 node->left = buildTree(nums, l, ind - 1); 27 node->right = buildTree(nums, ind + 1, r); 28 return node; 29 } 30 31 TreeNode* balanceBST(TreeNode* root) { 32 vector<TreeNode*> nums; 33 inorder(root, nums); 34 return buildTree(nums,0, nums.size() - 1); 35 } 36 };結構化思維
108. 將有序陣列轉換為二叉搜尋樹 : 結構化思維
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 * }; 11 */ 12 class Solution { 13 public: 14 TreeNode *buildTree(vector<int> &nums, int l, int r) { 15 if(l > r) return nullptr; 16 int mid = (l + r + 1) >> 1; 17 TreeNode *new_node = new TreeNode(nums[mid]); 18 new_node->left = buildTree(nums, l , mid - 1); 19 new_node->right = buildTree(nums, mid + 1, r); 20 return new_node; 21 } 22 23 TreeNode* sortedArrayToBST(vector<int>& nums) { 24 return buildTree(nums, 0, nums.size() - 1); 25 } 26 };結構化思維
98. 驗證二叉搜尋樹 : 結構化思維, 甚至可以理解為就是for 迴圈遍歷有序陣列;
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 * }; 11 */ 12 class Solution { 13 public: 14 TreeNode *pre; 15 bool __isValidVBST(TreeNode *root) { 16 if(!root) return true; 17 if(!__isValidVBST(root->left)) return false; 18 if(pre && pre->val >= root->val) return false; 19 pre = root; 20 if(!__isValidVBST(root->right)) return false; 21 return true; 22 } 23 bool isValidBST(TreeNode* root) { 24 pre = nullptr; 25 return __isValidVBST(root); 26 } 27 };結構化思維
劍指 Offer 33. 二叉搜尋樹的後序遍歷序列 : pre的使用在於它的定義,以及在結構化中的使用方式;與前/中/後 序都沒任何關係;前/中/後序都可以用pre實現按順序迴圈;
1 //結構化思維方式: 這裡是為了表達pre對於結構化思維意義; 2 //當然這裡pre初始值設定有缺陷(要取一個不在範圍內值); leetcode 23 個test case 可以過; 3 //fail case: [-6, -3, 9, -5, -1] 4 class Solution { 5 public: 6 int pre; 7 bool __postorder(vector<int>& nums, int l, int r) { 8 if(l >= r) return true; 9 int ind = l; 10 while(nums[ind] < nums[r]) ind++; 11 if(!__postorder(nums, l, ind - 1)) return false; 12 if(pre != -1 && nums[r] < pre) return false; 13 pre = nums[r]; 14 if(!__postorder(nums, ind, r - 1)) return false; 15 return true; 16 } 17 18 bool verifyPostorder(vector<int>& postorder) { 19 pre = -1; 20 return __postorder(postorder, 0, postorder.size() - 1); 21 } 22 }; 23 24 //orignial 25 class Solution { 26 public: 27 28 bool checkPostorder(vector<int> &nums, int l, int r) { 29 if(l >= r) return true; 30 int ind = l; 31 while(nums[ind] < nums[r]) ind++; 32 if(!checkPostorder(nums, l, ind - 1) || !checkPostorder(nums, ind, r - 1)) return false; 33 while(nums[ind] > nums[r]) ind++; 34 return ind == r; 35 } 36 37 38 bool verifyPostorder(vector<int>& postorder) { 39 return checkPostorder(postorder, 0, postorder.size() - 1); 40 } 41 };結構化思維/pre的意義
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode() : val(0), left(nullptr), right(nullptr) {} 8 * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} 9 * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} 10 * }; 11 */ 12 class Solution { 13 public: 14 TreeNode *buildTree(vector<int> &nums, int l, int r) { 15 if(l > r) return nullptr; 16 int ind = l + 1; 17 while(ind <= r && nums[ind] <= nums[l]) ind++; 18 TreeNode *node = new TreeNode(nums[l]); 19 node->left = buildTree(nums, l + 1, ind - 1); 20 node->right = buildTree(nums, ind, r); 21 return node; 22 } 23 24 TreeNode* bstFromPreorder(vector<int>& preorder) { 25 return buildTree(preorder, 0, preorder.size() - 1); 26 } 27 };結構化思維
思維鍛鍊結果檢驗:
面試題 04.09. 二叉搜尋樹序列: 對於vector<vector<int>> 套娃式結構中,對於空節點的返回值為vector<vector<int>>{vector<int>()};
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 void mergeSequence(vector<int>&l, int idx_l, vector<int>&r, int idx_r, vector<int> cur, vector<vector<int>> &ans) { 13 if(idx_l == l.size() || idx_r == r.size()) { 14 if(idx_l == l.size()) while(idx_r < r.size()) cur.push_back(r[idx_r++]); 15 else while(idx_l < l.size()) cur.push_back(l[idx_l++]); 16 ans.push_back(cur); 17 return; 18 } 19 20 cur.push_back(l[idx_l]); 21 mergeSequence(l, idx_l + 1, r, idx_r, cur, ans); 22 cur.pop_back(); 23 cur.push_back(r[idx_r]); 24 mergeSequence(l, idx_l, r, idx_r + 1, cur, ans); 25 return; 26 } 27 28 29 vector<vector<int>> BSTSequences(TreeNode* root) { 30 vector<vector<int>> ans; 31 if(!root) { 32 ans.push_back(vector<int>()); //對於vector<vector<int>>這類套圈的返回值對於nullptr 處理方案; 33 return ans; 34 } 35 vector<vector<int>> pre = BSTSequences(root->left), 36 next = BSTSequences(root->right); 37 38 vector<int> cur{root->val}; 39 for(int i = 0, I = pre.size(); i < I; ++i) { 40 for(int j = 0, J = next.size(); j < J; ++j) { 41 mergeSequence(pre[i], 0, next[j], 0, cur, ans); 42 } 43 } 44 return ans; 45 } 46 }; 47 48 //original 49 /** 50 * Definition for a binary tree node. 51 * struct TreeNode { 52 * int val; 53 * TreeNode *left; 54 * TreeNode *right; 55 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 56 * }; 57 */ 58 class Solution { 59 public: 60 void merge(vector<vector<int>> &ans, vector<int>&now, 61 vector<int> &l, int li, vector<int> &r, int ri) { 62 63 if(li == l.size() && ri == r.size()) { 64 ans.push_back(now); 65 return; 66 } 67 68 if(li < l.size()) { 69 now.push_back(l[li]); 70 merge(ans, now, l, li + 1, r, ri); 71 now.pop_back(); 72 } 73 if(ri < r.size()) { 74 now.push_back(r[ri]); 75 merge(ans, now, l, li, r, ri + 1); 76 now.pop_back(); 77 } 78 return; 79 } 80 81 82 vector<vector<int>> BSTSequences(TreeNode* root) { 83 vector<vector<int>> ans; 84 if(!root) { 85 ans.push_back(vector<int>()); 86 return ans; 87 } 88 89 vector<vector<int>> left = BSTSequences(root->left); 90 vector<vector<int>> right = BSTSequences(root->right); 91 92 vector<int> temp; 93 temp.push_back(root->val); 94 95 if(!left.size() && !right.size()) ans.push_back(temp); 96 for(int i = 0; i < left.size(); i++) { 97 for(int j = 0; j < right.size(); j++) { 98 merge(ans, temp, left[i], 0, right[j], 0); 99 } 100 } 101 102 return ans; 103 } 104 };結構化思維_檢查
======================= **應用場景** =======================
STL 中實現 map/set 的底層資料結構;