https://blog.csdn.net/luoshengkim/article/details/52103427
这是一道非常经典的二分查找题,给出一个有序数组以及一个目标值target,要求返回target在数组中的位置,若数组里不存在target,则返回-1。套用经典的二分查找模板即可:
//给出一个有序数组以及一个目标值target,要求返回target在数组中的位置,若数组里不存在target,则返回-1
class Solution {
public:
/**
* @param nums: An integer array sorted in ascending order
* @param target: An integer
* @return: An integer
*/
int findPosition(vector<int> &nums, int target) {
// write your code here
if (nums.size()== 0)
{
return -1;
}
int left = 0;
int right = nums.size() -1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]==target){
return mid;
}else if(nums[mid] < target){
left = mid+1;
}else if(nums[mid] > target){
right = mid -1;
}
}
return -1;
}
};
// 给定一个有序数组和一个目标值,要求在O(logn)的时间内找到那个目标值第一个出现的位置(数组中可能存在多个相同的目标值)
class Solution {
public:
/**
* @param nums: The integer array.
* @param target: Target to find.
* @return: The first position of target. Position starts from 0.
*/
int binarySearch(vector<int> &nums, int target) {
// write your code here
if (nums.size()== 0){
return -1;
}
int left = 0;
int right = nums.size() -1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]==target){
right = mid-1;
}else if(nums[mid] > target){
right = mid-1;
}else if(nums[mid] < target){
left = mid+1;
}
}
//没有找到或者超出边界,返回-1
if (left >= nums.size() || nums[left] != target){
return -1;
}
// 返回left 时,left已经是大于right的值,如果取小于的话,最终的返回值应该为left-1
return left;
}
};
// 给定一个有序数组和一个目标值,要求在O(logn)的时间内找到那个目标值最后1个出现的位置(数组中可能存在多个相同的目标值)
class Solution {
public:
/**
* @param nums: An integer array sorted in ascending order
* @param target: An integer
* @return: An integer
*/
int lastPosition(vector<int> &nums, int target) {
// write your code here
if (nums.size()== 0){
return -1;
}
int left = 0;
int right = nums.size() -1;
while(left<=right){
int mid = left + (right-left)/2;
if(nums[mid]==target){
left = mid+1;
}else if(nums[mid] > target){
right = mid-1;
}else if(nums[mid] < target){
left = mid+1;
}
}
//没有找到或者超出边界,返回-1
if (right < 0 || nums[right] != target){
return -1;
}
// 返回right 或者返回 left-1
return right;
}
};
// 在一个有序数组中,给定一个target,要求在数组中找到离target最近的数。
// Given [1, 4, 6] and target = 3, return 1.
// Given [1, 4, 6] and target = 5, return 1 or 2.
// Given [1, 3, 3, 4] and target = 2, return 0 or 1 or 2.
// 给定一个排序数组和一个目标值,如果在数组中找到目标值则返回索引。如果没有,返回到它将会被按顺序插入的位置。你可以假设在数组中无重复元素。
[1,3,5,6],5 → 2
[1,3,5,6],2 → 1
[1,3,5,6],7 → 4
[1,3,5,6],0 → 0
class Solution {
public:
/**
* @param A: an integer sorted array
* @param target: an integer to be inserted
* @return: An integer
*/
int searchInsert(vector<int> &A, int target) {
// write your code here
if(A.size() == 0){
return 0;
}
int left = 0;
int right = A.size()-1;
// 找到对应的数据则返回,找不到则再进行判断插入位置
while(left<= right){
int mid = left +(right-left)/2;
if(A[mid]==target){
return mid;
}else if(A[mid]<target){
left = mid+1;
}else if(A[mid]>target){
right = mid - 1;
}
}
if(A[right]<target){
return right+1;
}
if(A[right]>target){
return right;
}
return 0;
}
};
// 实现 int sqrt(int x) 函数,计算并返回 x 的平方根。
// 样例
// 样例 1:
// 输入: 0
// 输出: 0
// 样例 2:
// 输入: 3
// 输出: 1
// 样例解释:
// 返回对x开根号后向下取整的结果。
// 样例 3:
// 输入: 4
// 输出: 2
class Solution {
public:
/**
* @param x: An integer
* @return: The sqrt of x
*/
int sqrt(int x) {
// write your code here
int left = 0;
int right = x;
while (left<=right){
long mid = left + (right-left)/2;
if(mid*mid == x){
return mid;
}else if (mid*mid > x){
right = mid -1;
}else if (mid*mid < x){
left = mid +1;
}
}
if (right*right < x){
return right;
}
if (right*right > x)
{
return right-1;
}
}
};
//要求出一个数的开根号,只不过从整数换成了小数。当然小数是没办法精确地计算根号值的,只能近似的去模拟,比如误差不大于多少1e-10。
// 两种方案,一种用牛顿法,一种用二分查找法
#include <iostream>
#include <cmath>
using namespace std;
// err 是允许的误差
const double err = 1e-8;
double NtSqrt(const double num)
{
if (num < 0)
{
return -1;
}
else
{
double root = num;
// 如果原值减去近似根的平方大于误差,继续循环
while (abs(num - root * root) >= err)
{
// 得到下一个近似根
root = (num / root + root) / 2.0;
}
return root;
}
}
int main()
{
double num;
cout << "请输入一个数: ";
cin >> num;
double ans = NtSqrt(num);
if (ans == -1)
{
cout << "负数没有平方根" << endl;
}
else
{
cout << num << " 的平方根是 " << ans << endl;
}
return 0;
}
// 二分查找法
class Solution {
public:
/**
* @param x: a double
* @return: the square root of x
*/
double sqrt(double x) {
double result;
double start = 0, end, mid;
double origX = x;
if (x < 1) x = 1.0 / x;
end = x;
while(start + 1e-9 < end) {
mid = start + (end - start) / 2;
if (mid * mid < x) {
start = mid;
} else {
end = mid;
}
}
result = start + (end - start) / 2;
if (origX < 1) {
result = 1.0 / result;
}
return result;
}
};
<!-- 要自己实现一个求幂函数。
最直观容易想到的方法就是用递归方法求n个x的乘积,注意考虑n的正负号,时间复杂度为O(n) -->
// 先注意特殊情况,比如底数为0,或者小于0的情况,然后转换成一般情况
class Solution {
public:
/**
* @param x: the base number
* @param n: the power number
* @return: the result
*/
double myPow(double x, int n) {
// write your code here
if(n == 0){
return 1;
}
// 针对特殊溢出情况,加的补丁
if((n<=INT_MIN || n>=INT_MAX) && (x>1 || x<-1)) return 0;
if(x==1 && n==INT_MIN) return 1;
if(n<0){
return 1.0/myPow(x,-n);
}
double half = myPow(x,n/2);
if (n%2==0){
return half*half;
}
if (n%2==1){
return x*half*half;
}
}
};
<!-- 代码库的版本号是从 1 到 n 的整数。某一天,有人提交了错误版本的代码,因此造成自身及之后版本的代码在单元测试中均出错。请找出第一个错误的版本号。
你可以通过 isBadVersion 的接口来判断版本号 version 是否在单元测试中出错,具体接口详情和调用方法请见代码的注释部分。
样例
n = 5:
isBadVersion(3) -> false
isBadVersion(5) -> true
isBadVersion(4) -> true
因此可以确定第四个版本是第一个错误版本。
挑战
调用 isBadVersion 的次数越少越好
-->
/**
* class SVNRepo {
* public:
* static bool isBadVersion(int k);
* }
* you can use SVNRepo::isBadVersion(k) to judge whether
* the kth code version is bad or not.
*/
class Solution {
public:
/**
* @param n: An integer
* @return: An integer which is the first bad version.
*/
int findFirstBadVersion(int n) {
// write your code here
int left =1;
int right = n;
if (n==1){
return 1;
}
while(left <= right){
int mid = left + (right -left)/2;
if(SVNRepo::isBadVersion(mid)){
right = mid-1;
}else if (!SVNRepo::isBadVersion(mid)){
left = mid +1;
}
}
return left;
}
};
// 样例
// 例1:
// 输入: nums1 = [1, 2, 2, 1], nums2 = [2, 2],
// 输出: [2].
// 例2:
// 输入: nums1 = [1, 2], nums2 = [2],
// 输出: [2].
// 挑战
// 可以用三种不同的方法实现吗?
// 注意事项
// 结果中的每个元素必须是唯一的。
// 结果需要为升序。
// 解法一:用HashSet,扫描第一个数组,加进HashSet1中,得到的HashSet1是唯一的。然后扫描第二个数组,
// 如果第二个数组的元素在HashSet1中存在,则加进HashSet2中。最后得到的HashSet2就是答案了。
// 解法二:先排序,然后扫描第二个数组,在扫描第二个数组的过程中使用binarySearch,
// binarySearch即在第一个数组中找第二个数组的某个元素,如果找到了则加入HashSet,这样能保证答案是唯一的。
class Solution {
public:
/**
* @param nums1: an integer array
* @param nums2: an integer array
* @return: an integer array
*/
vector<int> intersection(vector<int> &nums1, vector<int> &nums2) {
// write your code here
set<int> setnums1(nums1.begin(),nums1.end());
set<int> reset;
for (int i = 0; i < nums2.size(); i++) {
/* code */
//如果某个数在数组1中出现过,但还没有被记录到交集结果数组中,则插入结果数组,set插入默认排序
if(setnums1.count(nums2[i])&&!reset.count(nums2[i])) reset.insert(nums2[i]);
}
return vector<int>(reset.begin(),reset.end());
}
};
<!--
样例1
输入:
nums1 = [1, 2, 2, 1], nums2 = [2, 2]
输出:
[2, 2]
样例2
输入:
nums1 = [1, 1, 2], nums2 = [1]
输出:
[1] -->
class Solution {
public:
/**
* @param nums1: an integer array
* @param nums2: an integer array
* @return: an integer array
*/
vector<int> intersection(vector<int> &nums1, vector<int> &nums2) {
int M = nums1.size();
int N = nums2.size();
if (M == 0 || N == 0) return vector<int>();
// 判断数组长度
vector<int> & large = (M >= N) ? nums1 : nums2;
vector<int> & small = (M < N) ? nums1 : nums2;
unordered_map<int, int> umLarge; //(number, freq)
// 遍历长数组,记录出现次数
for (int i = 0; i < large.size(); ++i) {
if (umLarge.find(large[i]) == umLarge.end()) {
umLarge[large[i]] = 1;
} else {
umLarge[large[i]]++;
}
}
vector<int> result;
//遍历短数组,并依照map计数,存储交集结果
for (int i = 0; i < small.size(); ++i) {
if (umLarge.find(small[i]) != umLarge.end() &&
umLarge[small[i]] > 0) {
result.push_back(small[i]);
umLarge[small[i]]--;
}
}
return result;
}
};
编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值。该矩阵具有如下特性:
- 每行中的整数从左到右按升序排列。
- 每行的第一个整数大于前一行的最后一个整数。
// 要求在一个二维数组中找到某个数target。这个矩阵具有以下特性:每行中的整数从左到右是排序的。每行的第一个数大于上一行的最后一个整数。
// 将二维数组看作有序一维数组,二分查找即可
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.empty()) return false;
int size_row = matrix.size(); //获取行数
int size_col = matrix[0].size(); //获取列数
int left = 0;
int right = size_row*size_col -1;
while(left<=right){
int mid = left + (right-left)/2;
if(matrix[mid/size_col][mid%size_col]==target){
return true;
}else if(matrix[mid/size_col][mid%size_col]>target){
right = mid -1;
}else if(matrix[mid/size_col][mid%size_col]<target){
left = mid +1;
}
}
return false;
}
};
240、搜索二维矩阵II
编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target。该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
示例:
现有矩阵 matrix 如下:
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]
给定 target = 5,返回 true。
给定 target = 20,返回 false。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if (matrix.size() == 0 || matrix[0].size() == 0) return false;
const int M = matrix.size(), N = matrix[0].size();
int i = M - 1, j = 0;
while (i >= 0 && j < N) {
if (matrix[i][j] == target) {
return true;
} else if (matrix[i][j] < target) {
++j;
} else {
--i;
}
}
return false;
}
};