直通BAT--数据结构与算法六(二分搜索)
2017-07-17 14:54
906 查看
二分法题解题技巧:
边界条件的考虑,中间划分点,循环终点的设定;
一般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<int> 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<int> 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;
}
边界条件的考虑,中间划分点,循环终点的设定;
一般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<int> 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<int> 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;
}
相关文章推荐
- 直通BAT--数据结构与算法十(排列组合)
- 插入算法 二分搜索 读数据结构与算法-C++
- 数据结构与算法以及leetcode刷题 012 二分搜索树
- 数据结构与算法(4)----->链表、二分搜索
- 数据结构与算法——搜索二叉树
- 数据结构与算法之搜索二叉树<五>
- 【数据结构与算法之查找算法二】二分查找
- Java数据结构与算法之【二分查找】
- 【数据结构与算法】二分查找
- [数据结构与算法]二叉排序(搜索)树实现
- 数据结构与算法--查找之顺序查找和二分查找
- 数据结构与算法-折半查找(二分查找)
- 【数据结构与算法】【查找】折半查找(二分查找)的代码实现
- C 数据结构与算法 二分查找
- [数据结构与算法] : 二分查找
- 【数据结构与算法】二分查找
- 数据结构与算法-----搜索和排序(C语言库函数的使用)
- ZH奶酪:【数据结构与算法】搜索之BFS
- 【数据结构与算法】二分类型 算法 怎么写
- 数据结构与算法-二分查找