• leetcode刷题笔录6


    验证二叉查找树

    • 给出一棵树,验证其是否是一棵二叉查找树。二叉查找树应当满足,对于每个节点:
      • 左子树中的所有节点的值小于该节点的值;
      • 右子树中的所有节点的值大于该节点的值;
      • 左子树和右子树都必须是二叉查找树。
    • 思路:递归检查每个节点的值是不是在某个区间 [min, max] 中,对根节点,检查其是不是在区间 [INT_MIN, INT_MAX] 中。对某个节点的检查区间,如此确定:如果该节点是父节点的左子结点,则 min 继承父节点检查区间的 min ,而 max 则为父节点的值;右子树类似。
    • 实现:
      /**
       * Definition for binary tree
       * struct TreeNode {
       *     int val;
       *     TreeNode *left;
       *     TreeNode *right;
       *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
       * };
       */
      class Solution {
      public:
          bool isValidBST(TreeNode *root) {
              return _isValidBST(root, INT_MIN, INT_MAX);
          }
          
          
          bool _isValidBST(TreeNode *root, int min, int max){
              if(root==NULL){
                  return true;
              }
              else{
                  if(root->val < min || root->val > max){
                      return false;
                  }
                  return _isValidBST(root->left, min, root->val-1) && _isValidBST(root->right, root->val+1, max);
              }
          }
      };

    恢复二叉查找树

    • 二叉查找树的两个节点被对调了,在不改变二叉树结构的情况下恢复之。
    • 思路:这样考虑,如果一个递增排列的数组中有两个元素被对调了,试图恢复之是较为简单的,只要稍微考虑一下边界条件即可。而此处是二叉树,我们只需要像顺序数组一样访问二叉树即可,即通过中序遍历一次访问各节点。
    • 实现:
      /**
       * 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) {
              node1 = NULL;
              node2 = NULL;
              preNode = NULL;
              inOrderDetect(root);
              
              if(node2 == NULL){
                  node2 = root;
                  while(node2->right){
                      node2=node2->right;
                  }
              }
              
              int tmp = node1->val;
              node1->val = node2->val;
              node2->val = tmp;
          }
          
          void inOrderDetect(TreeNode *root){
              if(root == NULL){
                  return;
              }        
              inOrderDetect(root->left);        
              if(preNode != NULL){
                  if(node1 == NULL){
                      if(root->val < preNode->val){
                          node1 = preNode;
                      }
                  }
                  else if(node2 == NULL){
                      if(root->val > node1->val){
                          node2 = preNode;
                      }
                  }
              }
              preNode = root;        
              inOrderDetect(root->right);
          }
          
          TreeNode* node1;
          TreeNode* node2;
          TreeNode* preNode;
      }; 

    字符串交错

    • 给出三个字符串 s1 和 s2 和 s3 ,判断 s3 是否是由 s1 和 s2 交错产生的。如 s1="aabcc",s2="dbbca",那么 s3="aadbbcbcac" 就是由前两个字符串交错产生的。
    • 思路:一看就知是动态规划问题。对于 s1[m1...m2],s2[n1...n2] 和 s3[p1...p2] (最初m1,n1,p1都为0),s3是否由 s1 和 s2 交错产生取决于:
      • 如果 s1[m1]!=s3[p1] 且 s2[m1]!=s3[p1],那么s3就不是由s1和s2交错产生,返回false;
      • 如果 s1[m1]==s3[p1] 且 s2[m1]!=s3[p1],那么就看 s1[m1+1...m2] 和 s2[n1...n2] 是否能够交错产生 s3[p1+1...p2];
      • 如果 s1[m1]!=s3[p1] 且 s2[m1]==s3[p1],和上一条类似。
      • 如果 s1[m1]==s3[p1] 且 s2[m1]==s3[p1],那么如果 s1[m1+1...m2] 和 s2[n1...n2] 能够交错产生 s3[p1+1...p2],或者 s1[m1...m2] 和 s2[n1+1...n2] 能够交错产生 s3[p1+1...p2],都返回 true。
    • 实现
      class Solution {
      public:
          bool isInterleave(string s1, string s2, string s3) {
      
              int mp = s1.length();
              int mq = s2.length();
              int mk = s3.length();
              if(mp+mq != mk){
                  return false;
              }
      
              vector<vector<int>> s(
                  mp+1,
                  vector<int>(mq+1, -1)
                  );
              return _isInterleave(s1, 0, s2, 0, s3, 0, s);
          }
      
          bool _isInterleave(string s1, int p, string s2, int q, string s3, int k, vector<vector<int>>& s){
      
              bool rslt = false;
      
              if(p==s1.length() && q==s2.length()){
                  return true;
              }
      
              if(s[p][q] == 1){
                  return true;
              }
              else if(s[p][q] == 0){
                  return false;
              }
      
              if(p<s1.length()){
                  if(s3[k]==s1[p]){
                      rslt = _isInterleave(s1, p+1, s2, q, s3, k+1, s) || rslt;
                  }
              }
              if(q<s2.length()){
                  if(s3[k]==s2[q]){
                      rslt = _isInterleave(s1, p, s2, q+1, s3, k+1, s) || rslt;
                  }
              }
      
              s[p][q] = rslt ? 1 : 0;
      
              return rslt;
          }
      }; 

    唯一二叉查找树1

    • 给出一个整数 n ,试问存储了 n 个不同的节点值的二叉查找树有多少种?比如给出3,返回5,因为有5种三个节点的二叉查找树,如下:
         1         3     3      2      1
          \       /     /      / \      \
           3     2     1      1   3      2
          /     /       \                 \
         2     1         2                 3
    • 思路:动态规划,二叉查找树的种类数 $f(n) = \sigma_{i=0}^{n}f(i)\cdot f(n-i)$,且 $f(0)=f(1)=1$,因为没有节点的二叉树和只有一个节点的二叉树都只有一种。
    • 实现:
      class Solution {
      public:
          int numTrees(int n) {
              vector<int> nums;
              nums.push_back(1);
              nums.push_back(1);
              for(int i=2; i<=n; i++){
                  int num = 0;
                  for(int j=0; j<i; j++){
                      num += nums[j-0]*nums[i-1-j];
                  }
                  nums.push_back(num);        
              }
              return nums[n];
          }    
      }; 

    唯一二叉查找树2

    • 同上一题,只不过需要输出所有可能的二叉查找树。
    • 思路:同上略。
    • 实现:
      /**
       * Definition for binary tree
       * struct TreeNode {
       *     int val;
       *     TreeNode *left;
       *     TreeNode *right;
       *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
       * };
       */
      class Solution {
      public:
          vector<TreeNode *> generateTrees(int n) {
              return _generateTrees(0, n-1);
          }
          
          vector<TreeNode *> _generateTrees(int n1, int n2){
              vector<TreeNode *> trees;
              if(n1>n2){
                  trees.push_back(NULL);
              }
              
              if(n1<=n2){
                  for(int i=n1; i<=n2; i++){
                      vector<TreeNode *> leftTrees = _generateTrees(n1, i-1);
                      vector<TreeNode *> rightTrees = _generateTrees(i+1, n2);
                      for(int p=0; p<leftTrees.size(); p++){
                          for(int q=0; q<rightTrees.size(); q++){
                              TreeNode* tree = new TreeNode(i+1);
                              tree->left = copyTree(leftTrees[p]);
                              tree->right = copyTree(rightTrees[q]);
                              trees.push_back(tree);
                          }
                      }
                  }
              }
              return trees;
          }
          
          TreeNode* copyTree(TreeNode* target){
              if(target==NULL){
                  return NULL;
              }
              TreeNode* node = new TreeNode(target->val);
              node->left = copyTree(target->left);
              node->right = copyTree(target->right);
              
              return node;
          }
      };

    二叉查找树的中序遍历

    • 不使用递归方法中序遍历输出二叉查找树
    • 思路:如果是递归的方法,那就很简单了。题目要求不用递归,而用循环来解决,那就需要借助一个栈来实现。栈中先压入一个空节点,然后令当前节点为根节点,并如下循环处理,直到当前节点为空(即栈空):
      • 如果当前节点是新获得的节点(而不是从栈中弹出),那就将其压入栈中,然后:
        • 如果该节点有左节点,那就令当前节点为左节点,进行下一次循环;
        • 如果当前节点没有左节点,那就将其弹出,当前节点不变(只不过现在不是新获得的节点了,而是从栈中弹出的节点),进行下一次循环;
      • 如果当前节点是从栈中弹出的节点,那就首先输出之(这是唯一输出该节点的地方,每个节点都经过这一步),然后:
        • 如果该节点有右节点,那就再从栈中弹出一个节点作为当前节点,进行下一次循环;
        • 如果该节点有有节点,就将当前节点设为有节点(注意该节点是新获得的节点),进行下一次循环。
    • 实现:
      /**
       * Definition for binary tree
       * struct TreeNode {
       *     int val;
       *     TreeNode *left;
       *     TreeNode *right;
       *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
       * };
       */
      class Solution {
      public:
          vector<int> inorderTraversal(TreeNode *root) {
              vector<int> rslt;
              stack<TreeNode*> stk;
              stk.push(NULL);
              
              TreeNode* node = root;
              bool nodeIsPoped = false;
              
              while(node!=NULL){
                  if(nodeIsPoped){
                      rslt.push_back(node->val);
                      if(node->right){
                          node = node->right;
                          nodeIsPoped = false;
                      }
                      else{
                          node = stk.top();
                          stk.pop();
                      }
                  }
                  else{
                      stk.push(node);
                      if(node->left){
                          node=node->left;
                      }
                      else{
                          node=stk.top();
                          stk.pop();
                          nodeIsPoped = true;
                      }
                  }
              }
              
              return rslt;
          }
      };
    作者:一叶斋主人
    出处:www.cnblogs.com/yiyezhai
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Web中的图标(Sprites雪碧图、Icon Font字体图标)
    那些不推荐使用的html标签
    Vim学习
    web前端性能优化建议
    开发基础
    数据库事务
    java集合详解
    java基础总结大纲(一)
    java设计模式之单例模式(饿汉)
    java设计模式之单例模式(内部静态类)
  • 原文地址:https://www.cnblogs.com/yiyezhai/p/3042011.html
Copyright © 2020-2023  润新知