【Day1 数组】二分查找和双指针思路和易错点归纳 | 代码随想录算法训练营

👉学习内容:数组理论基础;力扣第704题 二分查找;力扣第27题 移除元素

  1. 数组理论基础 文章链接

  2. 704. 二分查找 文章讲解 视频讲解
    题目建议: 熟悉 根据 左闭右开,左闭右闭 两种区间规则 写出来的二分法。
    拓展题型:
    35.搜索插入位置
    34.在排序数组中查找元素的第一个和最后一个位置

  3. 27. 移除元素
    文章讲解
    视频讲解
    题目建议:先把暴力写法写一遍。双指针法是本题的精髓。

一、数组理论基础

  • 内存地址(连续)、数组内容、下标(从0开始)
  • 16进制中,8+4=c=12(可以少占一位便于表示)
    啥
  • 数组元素不能删除,只能靠覆盖来操作

二、704. 二分查找

使用前提:数组为有序数组,同时题目还强调数组中无重复元素,因为一旦有重复元素,使用二分查找法返回的元素下标可能不是唯一的

💡关键问题在于对边界区间及开闭的处理:
①是>=还是> 【只有左闭右闭才是等于,如:[1,1]合法】

②是middle还是middle-1 【首先明确if里middle数值不等于target,所以替换时middle不能留在更新边界后的区间内。即:左闭右闭时都去掉;左闭右开时,右开本身不包含不用再去掉。】

  1. 复杂度分析
  • 时间复杂度:O(log⁡n),其中 n是数组的长度。
  • 空间复杂度:O(1)。
  1. 两种区间思路
  • 注:midlle与边界一方对比时都是纯大于小于号

左闭右闭速记

  • nums【-1】
  • while 【<=】
  • 右-1 ;左+1 (更新边界时)

int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]

while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=

if (nums[middle] > target) {
right = middle - 1; // target 在左区间,所以[left, middle - 1]

} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,所以[middle + 1, right]

左闭右开速记

  • nums【=】
  • while 【<】
  • 右= ;左边同上

int right = nums.size(); // 定义target在左闭右开的区间里,即:[left, right)

while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <

if (nums[middle] > target) {
right = middle; // target 在左区间,在[left, middle)中

} else if (nums[middle] < target) {
left = middle + 1; // target 在右区间,在[middle + 1, right)中

  1. 704题解
class Solution {
public:
    int search(vector<int>& nums, int target) {
    //int nums[] ={-1,0,3,5,9,12};
        int left = 0;
        int right = nums.size() - 1;
        while (left <= right) {
            int middle =(left + right)/2;
            //int middle = left + ((right - left) / 2);合并同类项后相同,写法不同,防止溢出
            if (nums[middle] > target){
                right = middle - 1;
            }else if (nums[middle] < target){
                left = middle +1;
            }else {
                return middle;
            }
        }
        return -1;
    }
};

💥易混淆:注意二分法原理、本题要求、left、right 以及 middle均为下标,只有nums[middle] 和target对应的为实际数值元素。

三、27. 移除元素

  1. 关于数组空间:
  • 数组是连续的,所以“移除”元素事实上是(后面的元素往前移动)“覆盖”元素,所以本题中本身在末尾的"val"值是不处理的,仅仅在返回size变量值(对元素计数操作)时进行减法,但实际上在size个元素后面可能还会有其他元素。如数组[1,3,5,2,3,2] 移除val = 2后,返回的数组个数size=4,减少两个,但是最终的数组为[1,3,5,3,2] 。不要误以为最后的2被删除了,因为智能覆盖。
  1. 在做题时是否直接调用库函数,要综合考虑两点:
  • 面试题目要看,该题目的是否为了考察原理,如果库只是其中的一小步,那就可以调用
  • 实际应用时,要综合考虑调用具体库的复杂度(所以要对复杂度有概念)。例如:erase函数看似是一步解决,但是其复杂度不是“删除”O(1),而是“覆盖”O(n)。
  1. 暴力解法思路
  • 一层for循环用来找元素
  • 一层for循环用来覆盖前面的元素
  1. 双指针速记
  • 快指针去找萝卜,慢指针挖坑。慢指针填完一个萝卜挖一个坑(slow ++),即慢指针填上一个元素就会指向下一个空位处,所以最后返回的slow值正好对应于前面的元素个数。slow为下标从0开始,最终的slow对应于最后一个没填的坑。
    在这里插入图片描述
  1. 题解
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;
    }
};
  • 28
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值