直通BAT--数据结构与算法六(二分搜索)

二分法题解题技巧:

  • 边界条件的考虑,中间划分点,循环终点的设定;
  • 一般mid=(left+right)/2,但是 left+right可能造成溢出,所以mid=left+(right-left)/2;
  • 演算判断终点条件是否有等于号;
  • 特殊情况要列举完全


 
1.arr中找到这个数出现的最左边的位置

//对于一个有序数组arr,再给定一个整数num,请在arr中找到num这个数出现的最左边的位置。
//给定一个数组arr及它的大小n,同时给定num。请返回所求位置。
//若该元素在数组中未出现,请返回 - 1。
//
//测试样例:
//[1, 2, 3, 3, 4], 5, 3
//返回:2

int LeftMostAppearance::leftMostAppearance(vector arr, int n, int num){

     int left = 0, right = n-1, mid = 0,res = 0;
     while (left <= right){
          mid = (left + right) / 2;
          if (arr[mid] == num){
              res = mid;
              right = mid - 1;
          }
          else if (arr[mid] > num){
              right = mid - 1;
          }
          else{
              left = mid + 1;
          }
     }
     return res;
}


2.循环有序数组最小值

//对于一个有序循环数组arr,返回arr中的最小值。有序循环数组是指,有序数组左边任意长度的部分放到右边去,右边的部分拿到左边来。比如数组[1, 2, 3, 3, 4],是有序循环数组,[4, 1, 2, 3, 3]也是。
//
//给定数组arr及它的大小n,请返回最小值。
//
//测试样例:
//[4, 1, 2, 3, 3], 5
//返回:1

int CircleArrayMin::circleArrayMin(vector arr, int n){

     //方法一:二分法
     if (arr.empty()){
          return -1;
     }
     if (arr.size() == 1){
          return 0;
     }
     //完全有序
     if (arr[0] < arr[n - 1]){
          return arr[0];
     }
     //最左边大于等于最右边,则最小值在其中
     int left = 0, right = n-1, mid = 0;
     while (arr[left] >= arr[right]){
          mid = (left + right) / 2;
          if (right - left == 1)
              return arr[right];
          if (arr[left] > arr[mid]){
              right = mid;
          }
          if (arr[right] < arr[mid]){
              left = mid;
          }
     }
     return arr[mid];

     //方法二:数组扫描
     /*if (arr.empty()){
          return -1;
     }
     if (arr.size() == 1){
          return arr[0];
     }
     if (arr[0] < arr[n-1]){
          return arr[0];
     }
     for (int i = 0; i < n - 1; ++i){
          if (arr[i + 1] < arr[i])
              return arr[i + 1];
     }
     return -1;*/
}


3.求一个整数的n次方

//如果更快的求一个整数k的n次方。
//如果两个整数相乘并得到结果的时间复杂度为O(1),得到整数k的N次方的过程请实现时间复杂度为O(logN)的方法。
//给定k和n,请返回k的n次方,为了防止溢出,请返回结果Mod 1000000007的值。
//
//测试样例:
//2, 3
//返回:8

int GetPowerValue::getPowerValue(int k, int N){
     long long tmp = k;
     long long res = 1;
     int m = 1000000007;
     for (; N > 0; N >>= 1){
          if ((N & 1) != 0){
              res *= tmp;
          }
          tmp = (tmp*tmp) % m;
          res = res % m;
     }

     return res;
}


4.完全二叉树节点个数

//给定一棵完全二叉树的根节点root,返回这棵树的节点个数。如果完全二叉树的节点数为N,请实现时间复杂度低于O(N)的解法。
//给定树的根结点root,请返回树的大小。

//计算2的n次方
int power(int n){
     int res = 1;

     for (int i = 0; i < n; ++i){
          res *= 2;
     }
     return res;
}

int CountTreeNodes::countTreeNodes(TreeNode* root){
     //判断是否左孩子、右孩子均为空,返回只有一个节点
     if (root->left == NULL && root->right == NULL){
          return 1;
     }
     //判断是否右孩子为空,返回有两个节点
     if (root->right == NULL){
          return 2;
     }

     //遍历左子树与右子树,计算树高度
     TreeNode* leftNode = root->left;
     TreeNode* rightNode = root->right;
     int lHeight = 1;
     int rHeight = 1;
     //总的节点数
     int nodes = 0;

     //计算左子树的高
     while (leftNode->left != NULL){
          ++lHeight;
          leftNode = leftNode->left;
     }
     //计算右子树的高
     while (rightNode->left != NULL){
          ++rHeight;
          rightNode = rightNode->left;
     }
     //左子树高大于右子树,则右子树为满二叉树,只需计算左子树
     if (lHeight > rHeight){
          nodes = power(rHeight);
          nodes += countTreeNodes(root->left);
     }
     //左子树高与右子树高相等,则左子树为满二叉树,只需计算右子树
     else{
          nodes = power(lHeight);
          nodes += countTreeNodes(root->right);
     }
     return nodes;
}

你可能感兴趣的:(C++)