引言
题目链接
34. 在排序数组中查找元素的第一个和最后一个位置 - 力扣(LeetCode)
第一题
这一题只要就是要我们用二分查找来实现一个对于左右区间的查找。这个和我们之前遇到的都不太一样,因为我们二分查找一般都是一个值。
所以我们就拿左区间 来举例子。我们这里选择的写法是 。假设我们要找8,【6 8 8 9】,我们要注意的是,二分查找法的目的是找一个值,所以那我们如果是左区间,就要让右边界right不断地往左边去靠,【8 8 8 8 8】假设我们的8很多,这个时候我们应该不断地移动right,所以这里地判断条件是numsmid >= target,同时把左边界赋值。**直到最后一个,**这个时候right--了,破坏了while的条件,但关键是这个操作仍然进行了,所以right最后一个指向其实是左边界地前面一个。所以在主函数里面return {left + 1, right - 1};这个操作结果可能和我们之前想的不是很一样,是因为我们之前地条件是判断==,如果相等返回,一直没有就返回没找到,根本不需要看这个左右区间的。而这个地方,我们不需要看是否相等,因为这个没有意义。
最后对于这个左右区间的结果处理,也比较有意思。因为如果target根本不在这个区间里面,那么left和right其中必定有一个是-2,假设我们在最右边,那么在计算左区间的时候,右边界根本不会移动。还有一种就是target没有找到,那这是最后一种情况,自然返回-1了
cpp
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int left = searchLeft(nums, target);
int right = searchRight(nums, target);
if(left == -2 || right == -2) {
return {-1, -1};
}
if(right - left > 1) {
return {left + 1, right - 1};
}
return {-1, -1};
}
private:
int searchLeft(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int leftRange = -2;
while(left <= right) {
int mid = left + ((right - left) / 2);
if(nums[mid] >= target) {
right = mid - 1;
leftRange = right;
} else {
left = mid + 1;
}
}
return leftRange;
}
int searchRight(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1;
int rightRange = -2;
while(left <= right) {
int mid = left + ((right - left) / 2);
if(nums[mid] <= target) {
left = mid + 1;
rightRange = left;
} else {
right = mid - 1;
}
}
return rightRange;
}
};
第二题
相对于两层for循环,一般来说,双指针可以完全代替两层for循环,用时间复杂度为O(n)的代码来解决问题
双指针的问题,本质上是一个快指针,一个慢指针。
在这一题里面,快指针的作用就是遍历整个数组,而慢指针的作用就是跟在屁股后面更新整个数组,凡是不对的,快指针跳过去,不让慢指针更新
cpp
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slow = 0;
for(int fast = 0; fast < nums.size(); fast++) {
if(nums[fast] != val) {
nums[slow] = nums[fast];
slow++;
}
}
return slow;
}
};
第三题
这个题要求的是把每个数平方之后再排序,因为数组原来就是有序的,但是因为负数的存在,所以最大的数永远是来自于最两侧,所以我们用left和right来表示最两侧的数据,然后每一次都选出最大的那一个数据,放入我们的新数组中res,也就是说我们的新数组是从最后面开始写入数据的。不过要注意的是我们结束的条件是left <= right,如果没有等于号,那么就会漏掉left和right相等时的那一个数据。
这里的k是新数组插入的索引
cpp
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int k = nums.size() - 1;
vector<int> res(nums.size(), 0);
for(int left = 0, right = nums.size() - 1; left <= right; ) {
if(nums[left] * nums[left] < nums[right] * nums[right]) {
res[k] = nums[right] * nums[right];
right--;
k--;
} else {
res[k] = nums[left] * nums[left];
left++;
k--;
}
}
return res;
}
};
第四题
这一题给我们了一个思路来求一个数的算数平方根。
我们还是可以用二分查找法来求,但是这个题目的要求是向下取整,所以我们需要对二分查找发有更加深刻的认识
首先我们的答案需要单独来计算,用ans,之前我们可以返回left,但是这里不可以,因为我们二分查找法找的是一个定值,但是这里一般都是小数,所以定值不存在,既然定值不存在,就不能在特定的位置返回,就不能得到我们想要的答案。所以我们记录ans的值,因为我们是不断的利用mid*mid来判断的,自然而然,mid就是我们最后要的答案。
注意一下,我们这里必须要在去等的地方对ans赋值,因为如果刚好相等了,但是你把这个值给跳过去了,那不是玩蛋蛋~~~
cpp
class Solution {
public:
int mySqrt(int x) {
int left = 0;
int right = x;
int ans = -1;
while(left <= right) {
int mid = left + (right - left) / 2;
if((long long)mid * mid <= x) {
left = mid + 1;
ans = mid;
} else {
right = mid - 1;
}
}
return ans;
}
};
总结
本篇主要是针对二分查找和双指针来记录的。希望可以对大家有所帮助!!!