类似题型[114.二叉树展开为链表] :
题目link;
解答link;
中序遍历的结果就是二叉搜索树所表示的有序数列,如中序遍历为 1 2 3 4 5 6 7 ,任意交换两节点由两种情况:
1、交换相邻两数 : 1 2 4 3 5 6 7
2、交换不相邻两数: 1 6 3 4 5 2 7
相邻两数只有一个逆序对, 交换之即可;
不相邻有两个逆序对,需要交换的是第一个逆序对的前一个数6与第二个逆序对的后一个数2。
如果是在空间复杂度为1的要求下, 使用morris算法如下:
Morris算法流程
1、如果当前节点没有左儿子,则打印当前节点的值,然后进入右子树;
2、如果 . 当前节点有左儿子,则寻找当前节点的前驱节点。
(1) 如果前驱节点的右儿子为空,说明左子树没有遍历过,则进入左子树遍历,并且将前驱节点的右儿子置为当前节点,方便回溯;
(2) 如果前驱节点的右儿子为当前节点,说明左子树已经被遍历过,则将前驱节点的右儿子恢复为空,然后打印该节点的值,然后进入右子树继续遍历。
下图为具体示例:
几个问题:
1、如何寻找一个节点的前驱节点?
首先进入左孩子,然后一直寻找右孩子,直至没有右孩子的那个节点即为前驱节点。
2、如何原地寻找逆序对?
需要一个父节点来记录。
代码
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
void recoverTree(TreeNode* root) {
TreeNode* last = NULL, *first = NULL, *second = NULL;
while (root) {
if (!root->left) {
if(last && last->val > root->val) {
if (!first) first = last;
second = root;
}
last = root;
root = root->right;
}
else {
auto p = root->left;
while (p->right && p->right != root) p = p->right; // 前驱节点p
if (!p->right) {
p->right = root;
root = root->left; //直接进入左节点,不需要进行比较
}
else {
p->right = NULL;
if(last && last->val > root->val) {
if (!first) first = last;
second = root;
}
last = root;
root = root->right;
}
}
}
swap(first->val, second->val);
}
};