力扣: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.我们可以遍历这个数组把各个元素与目标值target比较,如果相等直接返回对应下标就ok。
2.如果元素不存在,我们就要插入它的对应位置,按顺序的,所以插入到第一个大于它的元素前面就ok,对应位置就是第一个大于它的元素的下标,后面的元素后面移动就好了,此题不用,只用返回下标。
题解:
暴力解法
class Solution {
public int searchInsert(int[] nums, int target) {
for(int i = 0;i < nums.length;i++){
if(nums[i]>=target)
return i;
}
return nums.length;
}
}
- 时间复杂度:O(n)
- 空间复杂度:O(1)
二分法:1.元素在里面我们就正常找就是mid,2.目标值在数组所有元素之后right+1(left),3.目标值在数组所有元素之前right会到到下标-1,直接right+1(left)将好,4.需要插入到里面,因为没有这个元素left和right会相等,这个元素是左边以及它是小于目标值target,右边大于目标值target,最后一次循环有left+1或right-1,所以对应位置就是left或rigth+1
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0,right = nums.length - 1;
while(left<=right){
int mid = (right - left) / 2 + left;
int num = nums[mid];
if(num == target){
return mid;
}else if(num > target){
right = mid - 1;
}else{
left = mid + 1;
}
}
return left;
}
}
- 时间复杂度:O(log n)
- 空间复杂度:O(1)
34.在排序数组中查找元素的第一个和最后一个位置
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:你可以设计并实现时间复杂度为 $O(\log n)$ 的算法解决此问题吗?
示例 1:
- 输入:nums = [5,7,7,8,8,10], target = 8
- 输出:[3,4]
示例 2:
- 输入:nums = [5,7,7,8,8,10], target = 6
- 输出:[-1,-1]
示例 3:
- 输入:nums = [], target = 0
- 输出:[-1,-1]
思路:
方式一:1、首先,在 nums 数组中二分查找 target; 2、如果二分查找失败,则 binarySearch 返回 -1,表明 nums 中没有 target。此时,searchRange 直接返回 {-1, -1};3、如果二分查找成功,则 binarySearch 返回 nums 中值为 target 的一个下标。然后,通过左右滑动指针,来找到符合题意的区间
方式二:看了好久终于理解了,两步,先找到最右边的,再找到最左边的,右边:我们要一直先移动右边的指针,直到中间值小于等于目标值target 左边:我们要一直先移动左边的指针,直到中间值大于等于目标值target
题解:
方式一
class Solution {
public int[] searchRange(int[] nums, int target) {
int index = binarySearch(nums,target);
if(index == -1)//没有target值直接返回[-1,-1]
return new int[]{-1,-1};
//向左右移动找相同的值
int left = index,right = index;
//移动过程中left-1,right+1防止越界
while(left > 0 && nums[left-1]==nums[index]){
left--;
}
while(right < nums.length-1 && nums[right+1]==nums[index]){
right++;
}
return new int[]{left,right};
}
public int binarySearch(int[] nums, int target) {
int left = 0;
int right = nums.length - 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 {
right = mid - 1;
}
}
return -1;
}
}
方式二:
class Solution {
int[] searchRange(int[] nums, int target) {
int leftBorder = getLeftBorder(nums, target);
int rightBorder = getRightBorder(nums, target);
// 情况一
if (leftBorder == -2 || rightBorder == -2) return new int[]{-1, -1};
// 情况三
if (rightBorder - leftBorder > 1) return new int[]{leftBorder + 1, rightBorder - 1};
// 情况二
return new int[]{-1, -1};
}
int getRightBorder(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int rightBorder = -2; // 记录一下rightBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle - 1;
} else { // 寻找右边界,nums[middle] == target的时候更新left
left = middle + 1;
rightBorder = left;
}
}
return rightBorder;
}
int getLeftBorder(int[] nums, int target) {
int left = 0;
int right = nums.length - 1;
int leftBorder = -2; // 记录一下leftBorder没有被赋值的情况
while (left <= right) {
int middle = left + ((right - left) / 2);
if (nums[middle] >= target) { // 寻找左边界,nums[middle] == target的时候更新right
right = middle - 1;
leftBorder = right;
} else {
left = middle + 1;
}
}
return leftBorder;
}
}
69.x 的平方根
给你一个非负整数 x
,计算并返回 x
的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5)
或者 x ** 0.5
。
示例 1:
输入:x = 4 输出:2
示例 2:
输入:x = 8 输出:2 解释:8 的算术平方根是 2.82842..., 由于返回类型是整数,小数部分将被舍去。
思路:既然返回值是int类型,从1开始到x,计算i*i和(i+1)*(i+1)在这之间的就等于i。
题解:
暴力方法
class Solution {
public int mySqrt(int x) {
int num=0;
for(int i=1;i<=x;i++){
if(i*i<=x&&(long)(i+1)*(i+1)>x){
num=i;
break;
}
}
return num;
}
}
二分法:
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) mid * mid <= x) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}
}
367.有效的完全平方数
给你一个正整数 num
。如果 num
是一个完全平方数,则返回 true
,否则返回 false
。
完全平方数 是一个可以写成某个整数的平方的整数。换句话说,它可以写成某个整数和自身的乘积。
不能使用任何内置的库函数,如 sqrt
。
示例 1:
输入:num = 16 输出:true 解释:返回 true ,因为 4 * 4 = 16 且 4 是一个整数。
示例 2:
输入:num = 14 输出:false 解释:返回 false ,因为 3.742 * 3.742 = 14 但 3.742 不是一个整数。
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0, right = num;
while (left <= right) {
int mid = (right - left) / 2 + left;
long square = (long) mid * mid;
if (square < num) {
left = mid + 1;
} else if (square > num) {
right = mid - 1;
} else {
return true;
}
}
return false;
}
}