一刷代码随想录第一天 (数组、二分查找、移除元素)

数组基础理论

1、数组就是在内存连续储存的相同类型数据的集合。

2、数组的下标从0开始,可以很方便的使用下标进行寻址。

3、数组元素的删除必须改变其他元素的地址,且一般通过覆盖实现。

4、在Cpp中,二维数组的地址是连续的,但在其他语言中不一定。

704.二分查找

要求:在n个不重复元素升序排列的数组中查找Target位置并返回下标

基本原理:1、设定左右边界(一般使用左闭右开[left,right),左闭右闭[left,right])

2、将区间的中间元素(middle)与Target进行比较,若Target小于middle,则Target位于区间左侧,反之则位于区间右侧。位于左侧则更新右边界使区间在中间值左侧,同理右侧则更新左边界。

在对新边界进行middle更新

3、当其中一个middle等于Target时,返回middle就找到了,若没有一个middle满足条件则Target不在数组中。

4、其结束搜索的标志是出现不合法区间,如左闭右闭时leff>right,或左闭右开时left=right。

原理图如下

注意事项:二分法关键在与区间如何选取,不同的区间情况如何对左右边界进行更新。

例如:左闭右闭区间在更新左右边界时,要将以及判断过的middle进行排除,因为左闭右闭区间意味着,左右边界都可以取到,则必须排除以及判断过的值。而左闭右开则在更新右边界时,可以将上次判断的标志值作为右边界,因为它的右边界取不到。

代码如下(摘自代码随想录)

// 版本一(左闭右闭)
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() - 1; // 定义target在左闭右闭的区间里,[left, right]
        while (left <= right) { // 当left==right,区间[left, right]依然有效,所以用 <=
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle - 1; // target 在左区间,所以[left, middle - 1]
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right]
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

// 版本二(左闭右开)
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left = 0;
        int right = nums.size() ; // 定义target在左闭右开的区间里,[left, right)
        while (left <= right) { // 当left==right,区间[left, right)无效有效,所以用 <
            int middle = left + ((right - left) / 2);// 防止溢出 等同于(left + right)/2
            if (nums[middle] > target) {
                right = middle -; // target 在左区间,所以[left, middle - 1)
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,所以[middle + 1, right)
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

上述代码空间复杂度为O(1)

时间复杂度为O(logn)

27. 移除元素

要求:给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

基本原理:1、可以使用双重循环暴力解法,遍历数组找到相应的数据再让所有右侧元素左移覆盖,再记录发生左移次数,将数组最左侧的左移次数的元素清空即可。

2、可以利用双指针法,即分为一快一慢两重指针,快指针指向新数组中需要的元素,慢指针指向新数组的需要更新的元素位置,最后返回慢指针的下标则为新数组长度。

代码如下:

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

个人对双指针法的理解:相当于创建一个新的数组对数组进行赋值,快指针遍历数组并找出原始数组中新数组需要的元素,而慢指针则指向新数组对应元素的位置,遇到需要的元素 快指针与慢指针同步,就是一个萝卜一个坑,而遇到不需要元素,相当于遇到了不需要的萝卜,但坑还在那里,需要填了坑再往前进,快指针此时就会往下遍历找到需要的元素,放进慢指针指向的位置,最后形成新数组,一个萝卜一个坑,如果有不需要的萝卜,也就没必要有那么多坑,因此就可以坑不动,等下一个需要的萝卜,而当最后所有需要的元素都放进新数组中,慢指针还会往下前进一位,从最后一个更新的位置前进,此时慢指针代表的下标(从0开始)就是新数组的元素个数(从1开始).

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值