704. 二分查找 - 力扣(LeetCode)
给定一个
n个元素有序的(升序)整型数组nums和一个目标值target,写一个函数搜索nums中的target,如果target存在返回下标,否则返回-1。你必须编写一个具有
O(log n)时间复杂度的算法。
二分搜索法,思路较为简单,确定区间定义后,注意边界条件即可。
middle大,说明target在左半区间,让right为middle
middle小,说明target在右半区间,让left为middle
左闭右开
class Solution {
public:
int search(vector<int>& nums, int target) {
//左闭右开
int left = 0;
int right = nums.size(); //右侧是开区间,数组最大索引为size-1,因此右边界为size
int middle = 0;
while(left<right){ // [0,0)的区间无意义,左无法等于右
middle = left+(right-left)/2;
if(target<nums[middle]){ //middle不是目标
right = middle; //右为开,可以包含
}
else if(target>nums[middle]){ //middle不是目标
left = middle+1; //左为闭,不能包含
}
else return middle; // == 的情况
}
return -1;
}
};
左闭右闭
class Solution {
public:
int search(vector<int>& nums, int target) {
//左闭右闭
int left = 0;
int right = nums.size()-1; //右侧是闭区间,数组最大索引为size-1,因此右边界为size-1
int middle = 0;
while(left<=right){ // 存在[0,0]区间,左可以等于右
middle = left+(right-left)/2;
if(target<nums[middle]){
right = middle-1; //右为闭,不能包含
}
else if(target>nums[middle]){
left = middle+1;
}
else return middle;
}
return -1;
}
};
总结
Ⅰ细节:
-
middle = (right+left)/2可能会溢出 -
middle = left/2+right/2两次除法可能会超时 -
middle = left+(right-left)/2效率高且不会溢出
Ⅱ不同区间的选择,在代码上的区别主要有以下几处:
1.右边界初始化
-
左闭右闭 |
int right = nums.size()-1;|数组最大索引为size-1,闭区间时,右边界为最大索引 -
左闭右开 |
int right = nums.size();| 开区间时,右边界为最大索引+1
2.循环判断
-
左闭右闭 |
while(left<=right)|左右均闭,会出现左右边界相等的情况 -
左闭右开 |
while(left<right)| 不会出现相等的情况(若相等区间无意义)
3.更新右边界
-
左闭右闭 |
right = middle-1;|右闭,不能把middle再计入区间 -
左闭右开 |
right = middle;| 右开,边界为middle也不会考虑middle
27. 移除元素 - 力扣(LeetCode)
给你一个数组
nums和一个值val,你需要 原地 移除所有数值等于val的元素。元素的顺序可能发生改变。然后返回nums中与val不同的元素的数量。假设
nums中不等于val的元素数量为k,要通过此题,您需要执行以下操作:
- 更改
nums数组,使nums的前k个元素包含不等于val的元素。nums的其余元素和nums的大小并不重要。- 返回
k。
使用一快一慢双指针,fast遍历数组,slow维护新的数组(原数组原地修改) fast会在判断后把自己的值赋给slow,或者走在前面,因此slow原地修改当前数组不会影响fast的判断。
暴力 两层for
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
for(int i = 0;i<size;i++){
if(nums[i]==val){
for(int j = i;j<size-1;j++){
nums[j]= nums[j+1];
}//数组移动、依次覆盖
size--;//删了一个元素,数组大小减1
i--; //删了一个元素,索引也要回退,但实际上距离数组末尾距离不变
}
}
return size;
}
};
双指针
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
int fast = 0;
int slow = 0;
while(fast<size){
if(nums[fast]!=val){ //当前fast索引是想要的值(≠val)
nums[slow] = nums[fast]; //原地记录
slow++; //有效数组长度+1(根据题目,后面的不重要)
//同时也是下一个记录有效数字的索引位置
}
fast++;//不管怎样,fast都会前进,直到遍历原数组
}
return slow;
}
};
977. 有序数组的平方 - 力扣(LeetCode)
给你一个按 非递减顺序 排序的整数数组
nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
平方的大小取决于绝对值,由于非递减排序,绝对值可能出现先变小后变大的情况,因此最大的平方数只可能出现在头尾,故使用一左一右双指针遍历数组。
左右指针
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int size = nums.size();
vector<int> ans(size);
int left = 0;
int right = size-1;
int index = size-1;
while(left<=right){
//左大于等于,左记入数组,左加1
if(nums[left]*nums[left]>=nums[right]*nums[right]){
ans[index] = nums[left]*nums[left];
left++;
index--;
}
else{//右大,记入数组,右减1
ans[index] = nums[right]*nums[right];
right--;
index--;
}
}
return ans;
}
};
平方后排序
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
for(int i=0;i<nums.size();i++){
nums[i]=nums[i]*nums[i]; //平方
}
sort(nums.begin(),nums.end());//排序
return nums;
}
};
初次编辑于2025-10-10