数组(一)

前言

代码随想录day1,皆为LeetCode题。

共4题,知识点如下。

二分:
704. 二分查找、
705. 搜索插入位置、
706. 在排序数组中查找元素的第一个和最后一个位置。

双指针:
708. 移除元素。

模版

二分

bool check(int x) {/* ... */} // 检查x是否满足某种性质

// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;    // check()判断mid是否满足性质
        else l = mid + 1;
    }
    return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

r = mid , 就不需要补上加一
若是l = mid,那么前面是int mid = (l + r + 1)>> 1

教大家一个口诀 男左女右(判断为true时)

男是一 所以加一 女是零所以不用加

为什么要加1?

当l = r - 1的时候,如果不加1,mid = (2l + 1) / 2 = l
即没变,会死循环

双指针

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;

    // 具体问题的逻辑
}
常见问题分类:
    (1) 对于一个序列,用两个指针维护一段区间
    (2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作

704. 二分查找

模版题

仅特判一下不等于target的时候返回-1即可

class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0, r = nums.size() - 1;
        while (l < r) {
            int mid = l + r >> 1; 	// 在mid左边
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        }
        if (nums[r] != target) return -1;
        return r;
    }
};

35. 搜索插入位置

找到第一个大于等于当前数的位置,x >= target

可以插入到最后一个位置的后面,所以令r = num.size();

mid 向下取整,一定会小于size

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0, r = nums.size();

        while (l < r) {
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1;
        }
        return l;
    }
};

34. 在排序数组中查找元素的第一个和最后一个位置

删掉注释能从16ms降到4ms,牛的

先找左边界,此时条件为nums[mid] >= target,即第一个等于目标的位置

右边界条件为nums[mid] <= target,即最后一个等于目标的位置

在这里插入图片描述

class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        // 容易忘
        if (nums.empty()) return {-1, -1};

        // 找左边界
        int l = 0, r = nums.size() - 1;
        while (l < r) {
            int mid = l + r >> 1;
            if (nums[mid] >= target) r = mid;
            else l = mid + 1; 
        }
        // 没找到
        if (nums[r] != target) return {-1, -1};

        // 更新左边界为l或者r都行,此时相等
        int L = r; 

        // 找右边界
        l = 0, r = nums.size() - 1;
        while (l < r) {
            int mid = l + r + 1 >> 1;
            if (nums[mid] <= target) l = mid;
            else r = mid - 1;
        }
        return {L, r};
    }
};

27. 移除元素

例子

初始状况,上面的指针为指针1,下面的为指针2

在这里插入图片描述
指针1一直往后移,遍历所有值,所有值等于3的时候,指针2不变

刚开始值等于3,指针2不变,
当指针1移到值2时,指针2移动一位,此时数组为{2}

在这里插入图片描述

指针1又到3,指针2不变,指针1移到4的位置,指针2移动一位,此时数组为{2,4}

在这里插入图片描述

指针1移到值5,不等于3,指针2移动一位
最终数组值为{2,4,5}

在这里插入图片描述

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int k = 0;
        for (int i = 0; i < nums.size(); i++) 
            if (nums[i] != val) 
                nums[k ++] = nums[i];
        return k;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值