leetcode解题思路分析(十五)99 - 105题

  1. 恢复二叉搜索树
    二叉搜索树中的两个节点被错误地交换。请在不改变其结构的情况下,恢复这棵树。

本题的难点在于如何发现出错的节点,记录下来后交换。常规的做法分三步
(1)通过中序遍历获取一个排序数列
(2)找到排序数列中出问题的地方
(3)再次遍历找到出问题的位置并交换值
但是实际上,如果能在遍历过程中确定出问题的地方,即可以直接交换,算法会优化很多。这里可以采用迭代和递归只进行少于一次的遍历,它们都需要高达O(H) 的空间来保存堆栈,其中 H 指的是树的高度。Morris 算法是遍历两次的方法,但它是一个常数级空间的方法

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    void swap(TreeNode *a, TreeNode *b) 
    {
        int tmp = a->val;
        a->val = b->val;
        b->val = tmp;
    }

    void recoverTree(TreeNode *root) 
    {
        // predecessor is a Morris predecessor. 
        // In the 'loop' cases it could be equal to the node itself predecessor == root.
        // pred is a 'true' predecessor, 
        // the previous node in the inorder traversal.
        TreeNode *x = NULL, *y = NULL, *pred = NULL, *predecessor = NULL;

        while (root != NULL) {
        // If there is a left child
        // then compute the predecessor.
        // If there is no link predecessor.right = root --> set it.
        // If there is a link predecessor.right = root --> break it.
        if (root->left != NULL) {
            // Predecessor node is one step left 
            // and then right till you can.
            predecessor = root->left;
            while (predecessor->right != NULL && predecessor->right != root)
            predecessor = predecessor->right;

            // set link predecessor.right = root
            // and go to explore left subtree
            if (predecessor->right == NULL) {
            predecessor->right = root;
            root = root->left;
            }
            // break link predecessor.right = root
            // link is broken : time to change subtree and go right
            else {
            // check for the swapped nodes
            if (pred != NULL && root->val < pred->val) {
                y = root;
                if (x == NULL) x = pred;
            }
            pred = root;

            predecessor->right = NULL;
            root = root->right;
            }
        }
        // If there is no left child
        // then just go right.
        else {
            // check for the swapped nodes
            if (pred != NULL && root->val < pred->val) {
            y = root;
            if (x == NULL) x = pred;
            }
            pred = root;

            root = root->right;
        }
        }
        swap(x, y);
  }
};

  1. 相同的树
    给定两个二叉树,编写一个函数来检验它们是否相同。
    如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

很简单,遍历比较即可

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSameTree(TreeNode* p, TreeNode* q) {
        if (p == NULL && q == NULL)
            return true;
        else if (p == NULL || q == NULL)
            return false;
            
        if (p->val != q->val)
            return false;
        if (p->left == NULL && q->left == NULL
            && p->right == NULL && q->right == NULL
            && p->val == q->val)
            return true;
        
        if (isSameTree(p->left, q->left) && 
            isSameTree(p->right, q->right))
            return true;
        else return false;
    }
};
  1. 对称二叉树
    给定一个二叉树,检查它是否是镜像对称的。

本题可以采用递归求解,依次判断左子树的左子树和右子树的右子树以及左子树的右子树和右子树的左子树即可。也可以采用队列或者堆栈,原理相同。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        if (root == NULL)
            return true;
        else 
            return isSame(root->left, root->right);
    }

    bool isSame(TreeNode *lhs, TreeNode *rhs)
    {
        if (lhs == NULL && rhs == NULL)
            return true;
        else if (lhs == NULL || rhs == NULL)
            return false;

        if (lhs->val == rhs->val)
            return (isSame(lhs->left, rhs->right) && 
                isSame(lhs->right, rhs->left));
        else return false;
    }
};
  1. 二叉树的层次遍历
    给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。

对于普通遍历多一个变量记录层级即可,然后对应层级记录

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    vector<vector<int>> ret;
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        search(root, 0);
        return ret;
    }

    void search(TreeNode *root, int height)
    {
        if (root == NULL)
            return;

        if(ret.size() == height)       
            ret.resize(height + 1);

        ret[height].push_back(root->val);
        height++;
        search(root->left, height);
        search(root->right, height);
    }
};
  1. 二叉树的锯齿形层次遍历
    给定一个二叉树,返回其节点值的锯齿形层次遍历。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。

本题和上题其实没啥区别,加一个层级判断从前或者从后插入即可

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    vector<vector<int>> ret;
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        search(root, 0);
        return ret;
    }

    void search(TreeNode *root, int height)
    {
        if (root == NULL)
            return;

        if(ret.size() == height)       
            ret.resize(height + 1);
        if (height % 2 == 0)
            ret[height].push_back(root->val);
        else ret[height].insert(ret[height].begin(), root->val);
        height++;
        search(root->left, height);
        search(root->right, height);
    }   
};
  1. 二叉树的最大深度

很简单的一道题,遍历同时记录大小并存最大值即可

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
    int max = 0;
public:
    int maxDepth(TreeNode* root) {
        int height = 0;
        search(root, height);
        return max;
    }
    void search(TreeNode *root, int height)
    {
        if (root == NULL)
            return;
        else
        {
            height++;
            if (height > max)
                max = height;
            search(root->left, height);
            search(root->right, height);
        }
    }

};
  1. 从前序与中序遍历序列构造二叉树

本题的核心思想在于前序的开始为根节点,而中序根节点左侧为左子树,因此可以递归查找:每次由前序判断根,由中序判断左右子树,然后左右子树按照这个规律继续判断,直到没有节点为止

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int pos = 0;
        return buildTree(preorder, pos, inorder, 0, inorder.size() - 1);
    }

    TreeNode* buildTree(vector<int>& preorder, int& pos, vector<int>& inorder, int left, int right) 
    {
        if (pos >= preorder.size()) 
            return 0;

        int i = left;

        // 搜索到目前的根在中序的位置i
        for (; i <= right; ++i) 
        {
            if (inorder[i] == preorder[pos]) 
                break;
        }

        // 当前的根为前序的pos
        TreeNode* node = new TreeNode(preorder[pos]);

        // 当左边只剩一个就不用递归了
        if (left <= i - 1) 
            node->left = buildTree(preorder, ++pos, inorder, left, i - 1);  // 左子树

        // 当右边只剩一个也是不用了
        if (i + 1 <= right) 
            node->right = buildTree(preorder, ++pos, inorder, i + 1, right);  // 右子树

        return node;
    }
};

你可能感兴趣的:(面试,leetcode,二叉树,算法,数据结构)