Day1 | 704. 二分查找 27.移除元素 977.有序数组的平方 | [二分查找][双指针]

86 阅读4分钟

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