• leetcode刷题笔录6


     

    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)=σni=0f(i)f(ni),且 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
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     

    验证二叉查找树

    • 给出一棵树,验证其是否是一棵二叉查找树。二叉查找树应当满足,对于每个节点:
      • 左子树中的所有节点的值小于该节点的值;
      • 右子树中的所有节点的值大于该节点的值;
      • 左子树和右子树都必须是二叉查找树。
    • 思路:递归检查每个节点的值是不是在某个区间 [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)=σni=0f(i)f(ni),且 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
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     

    如:-5,7,1,9,-12,15 变成 -5,-12,7,1,9,15。如何解?

    题目要求:
    空间复杂度O(1),时间复杂度O(N),排序稳定。

    空间上只能利用循环变量,标记变量等;时间上可以说是过一遍数组就完事了。

    分治

    用分治可以解决问题:首先把规模为 N 的问题划分成两个规模近似为 N/2 的子问题,两个子问题得到解决后进行合并得到整个问题的答案。对于本篇的问题,主要考虑合并该怎么解决,也就是假设:

    将数组 arr 分成 arr1 和 arr2。设 arr1 为 [----++++],arr2 为 [------+++],如何得到 arr 为 [----------+++++++]。

    显然,只要将 arr1 的所有正数和 arr2 的所有负数交换就好了,为了不打乱原有正数/负数的次序,而且不借用任何其他的空间,考虑用《编程珠玑》中提到的 Doug Mcllroy 提出的翻手例子:

    0_1320473198JbmS

    翻手代码在时间和空间上都很高效,而且代码非常的简短,很难出错。

    于是方法是:将 arr1 中的正数 reverse 一次,arr2 中的负数 reverse 一次,紧接着 arr1 中的正数和 arr2 中的 负数结合起来 reverse 一次,由此完成 arr1 和 arr2 的合并。子问题就解决了。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    void merge(int *arr,int left,int middle,int right)
    {
        /*全负数*/    /*全正数*/
        if(!(arr[middle]>0 && arr[middle+1]<0))
            return;
     
        //    找到 +++++ ----- 区域
        int pos1 = left,pos2 = middle + 1;
        for(int i=left; i<=middle; i++)
            if(arr[i] > 0)    {pos1 = i;break;}
        for(i=middle+1; i<=right; i++)
            if(arr[i] > 0)    {pos2 = i-1;break;}
     
        //    翻手定律,你懂得
        reverse(arr+pos1,middle - pos1+1);
        reverse(arr+middle+1,pos2 - middle);
        reverse(arr+pos1,pos2 - pos1 + 1);
    }

    迭代

    另外,通过翻手方法同样可以迭代解决这个问题,也就是把 arr 走一遍就可以解决。同样,具体举例:

    [……-+++--+-……]

    1. 刚开始扫描的时候如果一直是负数,那么不用作任何的动作
    2. 关键是遇上 [+++--] 的时候,需要作翻手处理,从而交换 [+++] 和 [--] 得到:[……---++++-……]
    3. 继续扫描得到 [+],[……---++++-……],不用处理
    4. 继续扫描得到 [-],[……---++++-……],需要对 [++++-] 作翻手处理,从而交换 [++++] 和 [-] 得到:[……----++++……](此步骤和步骤 2 情况相同)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    void myfunc(int *arr,int left,int right)
    {
        if(right <= left)
            return;
     
        bool f = false;        //    flag = true    表示需要进行翻转
        int posbeg = -1,    //    正数开始
            posend,            //    正数结束
            negbeg,            //    负数开始
            negend,            //    负数结束
            negcount = 0;    //    负数统计
     
        for(int i = 0; i<=right; i++)
        {
            if(arr[i]>0)
            {
                if(posbeg < 0)
                    posend = posbeg = i;
                posend = i;
                for(int j=i+1; j<=right; j++)
                    if(arr[j]>0)posend++;
                    else break;
                f = true;
                i = posend + 1;
            }
     
            if(arr[i] < 0 && i <= right)
            {
                if(!f){negcount++;continue;}
                negend = negbeg = i;
                for(int j=i+1; j<=right; j++)
                    if(arr[j]<0)negend++,negcount++;
                    else break;
                i = negend;       
     
                reverse(arr+posbeg,posend-posbeg+1);
                reverse(arr+negbeg,negend-negbeg+1);
                reverse(arr+posbeg,negend-posbeg+1);
                f = false;print(arr,14);
                posend = negend;
                posbeg = negcount + 1;
            }
     
        }//    while
    }

    算法复杂度

    在空间上符合题目条件,但在时间上有待讨论,时间上的消耗主要在 for 循环里面的 reverse 操作。假设 arr 数组当中有 m 个正数和 n-m 的负数,在最坏的情况下,复杂度是 O(m(n-m)),平摊给 for 循环的 n 次操作,那么结果是 O(m-m^2/n))。因此,此算法不稳定。

    我们来看看根据 n 和 m 的不同模拟的函数图像,将函数写成 y = x-x^2/k:

    未命名

    由此,这种算法确实很不稳定。一开始以为平摊法可以解决复杂度分析问题,可以达到 O(N) 的效果,但无果而终。在 CSDN 上有这题的讨论:腾讯面试题:把负数移动到正数之前,不能改变正负数原先的次序 和 微博的一个编程题 。如果你有什么好的想法,不忘给我和网友们分享一下 :),据说「之前百度就出过这道题,讨论了1000楼都没有一个正确答案」。

    捣乱 2013-05-03

    http://daoluan.net

     
     
    分类: Algorithm

    面试题:把负数移动到正数之前,不能改变正负数原先的次序

  • 相关阅读:
    java poi 从服务器下载模板写入数据再导出
    一个华为面试题
    ForEach 循环
    fmt标签格式化数字和时间
    Ichars制作数据统计图
    jQuery中的事件
    oracle学习第四天
    GET请求和POST请求
    Jsp的九个隐含对象
    Oracle学习【语句查询】
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3057460.html
Copyright © 2020-2023  润新知