代码随想录算法训练营第一天 |二分 + 双指针

数组

二分查找

二分查找的操作对象是区间,理清二分查找的思路需要时刻关注区间的变化
需要注意的是如果进行l = mid操作,需要格外注意死循环的问题(因为mid = l + r >> 1)

(1)左闭右闭区间
//右闭,r要往前一位
int l = 0, r = nums.size() - 1;
//左闭右闭区间中l == r合法
while(l <= r){
    int mid = l + (r - l) / 2;  //防止溢出
    if(nums[mid] > target) r = mid - 1;
    else if(nums[mid] < target) l = mid + 1;
    else return mid;
}
return -1;
( 2)左闭右开区间
//右开,r不需要前移
int l = 0, r = nums.size();
//左闭右开区间中l == r不合法
while(l < r){
    int mid = l + (r - l) / 2;  //防止溢出
    //右开,r不包含mid,不需要-1
    if(nums[mid] > target) r = mid;
    else if(nums[mid] < target) l = mid + 1;
    else return mid;
}
return -1;
题目
力扣704.二分查找

模板题

力扣35.搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

示例:

输入: nums = [1,3,5,6], target = 2
输出: 1

对于目标值不存在的处理:

/*执行r = mid - 1后跳出循环
即l == r处的值大于target
则target应该插入在l == r处
而r的值已经被更新,则返回l*/
if(r < l) return l;
else return r;

完整代码:

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0, r = nums.size() - 1;
        while(l <= r){
            int mid = (l + r) / 2;
            if(nums[mid] > target) r = mid - 1;
            else if(nums[mid] < target) l = mid + 1;
            else return mid;
        }
        if(r < l) return l;
        else return r;
    }
};
力扣34.在排序数组中查找元素的第一个和最后一个位置

给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。

示例:

输入:nums = [5,7,7,8,8,10], target = 8
输出:[3,4]

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> res = {-1, -1};
        int l = 0, r = nums.size() - 1;
        while(l <= r){
            int mid = (l + r) / 2;
            if(nums[mid] > target) r = mid - 1;
            else if(nums[mid] < target) l = mid + 1;
            //找到了中间值的下标,然后利用中间值的下标分别寻找左右端点
            else{
                int l1 = l, r1 = r;
                while(nums[l1] != target){
                    mid = (l1 + r1) / 2;
                    if(nums[mid] > target) r1 = mid - 1;
                    else if(nums[mid] == target){
                        r1 = mid;
                        l1 += 1;
                    }
                    else l1 = mid + 1;
                }
                res[0] = l1;

                int l2 = l, r2 = r;
                while(nums[r2] != target){
                    mid = (l2 + r2) / 2;
                    if(nums[mid] > target) r2 = mid - 1;
                    //因为是把mid赋值给左端点,所以要防止死循环
                    else if(nums[mid] == target){
                        l2 = mid;
                        r2 -= 1;
                    }
                    else l2 = mid + 1;
                }
                res[1] = r2;

                return res;
            }
        }
        return res;
    }
};

双指针算法

题目
力扣27.移除元素

暴力解法:

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 + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                i--; // 因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--; // 此时数组的大小-1
            }
        }
        return size;

    }
};

暴力优化解法:

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int num = 0;
        for(int i = 0; i < nums.size(); i ++ )
            if(nums[i] != val) nums[i - num] = nums[i];
            else num ++;
        return nums.size() - num;
    }
};

双指针算法(快慢指针法):

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
            //fastIndex不指向val则一起前进(相当于用第二个数组)
            //fastIndex指向val时只有fastIndex前进
            if (val != nums[fastIndex]) {
                nums[slowIndex++] = nums[fastIndex];
            }
        }
        return slowIndex;
    }
};

双指针算法(相向指针法):

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int leftIndex = 0;
        int rightIndex = nums.size() - 1;
        while (leftIndex <= rightIndex) {
            // 找左边等于val的元素
            while (leftIndex <= rightIndex && nums[leftIndex] != val){
                ++leftIndex;
            }
            // 找右边不等于val的元素
            while (leftIndex <= rightIndex && nums[rightIndex] == val) {
                -- rightIndex;
            }
            // 将右边不等于val的元素覆盖左边等于val的元素
            if (leftIndex < rightIndex) {
                nums[leftIndex++] = nums[rightIndex--];
            }
        }
        return leftIndex;   // leftIndex一定指向了最终数组末尾的下一个元素
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值