1[Leetcode 35]给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为
O(log n)
的算法。示例 1:
输入: nums = [1,3,5,6], target = 5 输出: 2示例 2:
输入: nums = [1,3,5,6], target = 2 输出: 1示例 3:
输入: nums = [1,3,5,6], target = 7 输出: 4提示:
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums
为 无重复元素 的 升序 排列数组-104 <= target <= 104
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int low=0,high=nums.size()-1,mid;
while(low<=high)
{
mid=low+(high-low)/2;
if(nums[mid]==target) return mid;
else if(nums[mid]<target) low=mid+1;
else high=mid-1;
}
return low;
}
};
分析:典型的二分搜索,不难发现规律,当搜索不到该元素时,low所在位置即元素应插入位置
时间复杂度:O(logn)
空间复杂度:O(1)
2.[leetcode 34]
给你一个按照非递减顺序排列的整数数组
nums
,和一个目标值target
。请你找出给定目标值在数组中的开始位置和结束位置。如果数组中不存在目标值
target
,返回[-1, -1]
。你必须设计并实现时间复杂度为
O(log n)
的算法解决此问题。
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int first=searchFirst(nums,target); //左边界
int last=searchLast(nums,target); //右边界
vector<int> range{first,last};
return range;
}
private:
//寻找左边界
int searchFirst(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(nums[mid]==target){
//如果前一个元素比目标值小则说明已找到左边界
if(mid==0||nums[mid-1]<nums[mid])
return mid;
//否则将区间往左边压缩继续搜索
right=mid-1;
}
else if(nums[mid]<target)
left=mid+1;
else right=mid-1;
}
return -1;//没搜到返回-1
}
//寻找右边界
int searchLast(vector<int>& nums, int target) {
int left=0;
int right=nums.size()-1;
while(left<=right)
{
int mid=left+(right-left)/2;
if(nums[mid]==target){
//如果后一个元素比目标值大则说明已找到右边界
if(mid==nums.size()-1||nums[mid+1]>nums[mid])
return mid;
//否则将区间往右边压缩继续搜索
left=mid+1;
}
else if(nums[mid]<target)
left=mid+1;
else right=mid-1;
}
return -1;//没搜到返回-1
}
};
分析:基于二分查找法进行修改,核心是弄清在搜索到匹配值时何时返回,何时继续压缩区间
时间复杂度:O(logn)
空间复杂度:O(1)
3.[leetcode 69]
给你一个非负整数
x
,计算并返回x
的 算术平方根 。由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如
pow(x, 0.5)
或者x ** 0.5
。
解法一:二分法
class Solution { public: int mySqrt(int x) { int l = 0, r = x, ans = -1; while (l <= r) { int mid = l + (r - l) / 2; if ((long long)mid * mid <= x) //long long 防溢出 { ans = mid; l = mid + 1; } else { r = mid - 1; } } return ans; } };
分析:这个二分查找法要搜索的对象是平方小于等于x的最大整数
时间复杂度:O(logx)
空间复杂度: O(1)
解法二:暴力匹配
class Solution {
public:
int mySqrt(int x) {
int i=1;
while((long long)i*i<=x) i++;
return i-1;
}
};
时间复杂度:O(根号n)
空间复杂度: O(1)
值得注意的是:根号n的时间复杂度高于logn的时间复杂度
解法三:e、ln计算器
class Solution { public: int mySqrt(int x) { int ans=1/2.0*exp(1/2.0*log(x)); return (ans+1)*(ans+1)<=x?ans+1:ans; } };
分析:由于计算精度问题,需检验ans和ans+1哪个是正确答案
时间复杂度:O(1)
空间复杂度:O(1)
4.[Leetcode 369]
给你一个正整数
num
。如果num
是一个完全平方数,则返回true
,否则返回false
。完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。
不能使用任何内置的库函数,如
sqrt
。
class Solution {
public:
bool isPerfectSquare(int num) {
int l = 0, r = num, ans = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if ((long long)mid * mid <= num) {//long long 防溢出 {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
if(ans*ans==num) return true;
return false;
}
};
分析:基于上一道题写难度就不大了 ,上面展示用二分法完成,当搜索到的ans正好是开根数,则说明num为完全平方数
时间复杂度:O(logn)
空间复杂度:O(1)