题目:二叉树中有两个节点对换了值,恢复他们。
思路:
因为中序遍历是有序的,如果中序遍历后的数组出现乱序,说明就是交换的。从前往后,第一次乱序的第一个,后最后一次乱序的后一个,然后把这两个值对换就好了。
想了个非常挫的办法。
先中序遍历Binary Tree Inorder Traversal,然后在数组中找到两个值,然后再中序遍历找到那两个值,交换一下。虽然AC了,但不忍直视啊。
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: void inorder(TreeNode *root, vector<int> &perm) // 中序遍历得到数组 { if (root == NULL) return ; stack<TreeNode *> sta; sta.push(root); TreeNode *p = root -> left, *cen; while(!sta.empty()) { if (p) { sta.push(p); p = p -> left; } else { cen = sta.top(); sta.pop(); perm.push_back(cen -> val); if (cen -> right) { sta.push(cen -> right); p = cen -> right -> left; } } } } void inorderC(TreeNode *root,int val1, int val2) // 中序遍历将对应值修改 { if (root == NULL) return ; stack<TreeNode *> sta; sta.push(root); TreeNode *p = root -> left, *cen; while(!sta.empty()) { if (p) { sta.push(p); p = p -> left; } else { cen = sta.top(); sta.pop(); if(cen -> val == val1) cen -> val = val2; else if(cen -> val == val2) cen -> val = val1; if (cen -> right) { sta.push(cen -> right); p = cen -> right -> left; } } } } void recoverTree(TreeNode *root) { if (!root) return ; vector<int> perm; inorder(root, perm); int val1, val2; bool flag = true; for (int i = 0; i < perm.size(); ++i) { if (flag && i + 1 < perm.size() && perm[i] > perm[i+1]) // 第一次比后一个大的数 { val1 = perm[i]; flag = false; } if (i - 1 >= 0 && perm[i] < perm[i-1]) // 最后一个比前面小的数 val2 = perm[i]; } inorderC(root, val1, val2); } };
然后就想到改进,在一次中序遍历中就记录两个节点,然后交换值。
经过优化之后果然好看多了。
/** * Definition for binary tree * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: void recoverTree(TreeNode *root) { if (!root) return ; stack<TreeNode *> sta; vector<int> perm; TreeNode *p = root, *sw1, *sw2, *pre = NULL; bool flag1 = false; // 分别表示sw1是否找到 while(p || !sta.empty()) { while(p) { sta.push(p); p = p -> left; } if (!sta.empty()) { p = sta.top(); // 在//这之间和pre比较 if (pre && !flag1 && pre -> val > p -> val) { sw1 = pre; flag1 = true; // sw1是第一次违法的第一个数 } if (pre && pre -> val > p -> val) { sw2 = p; // sw2是最后一次违法的第二个数 } // sta.pop(); pre = p; // 每次加入的对应pre;下一次要加入的时候那么pre就是之前一个了 perm.push_back(p -> val); p = p -> right; } } swap(sw1->val, sw2->val); return ; } };