算法训练第一天|数组理论基础,704. 二分查找,27. 移除元素

数组理论基础

 

数组——存放在连续内存空间上的相同类型数据的集合

在C++中,vector和array的区别,vector的底层实现是array,vector的本质是容器不是数组

在C++中,二维数组是连续分布的

Leetcode 704二分查找

Leetcode题目链接

力扣https://leetcode.cn/problems/binary-search/

给定一个n个元素有序的整型数组和一个target,写一个函数搜索nums中的target,如果存在返回下标,不存在返回-1

重点——区间问题

[left, riht]左闭右闭,[left,right)左闭右开

左闭右闭——[left,right]

left = 0

right = num_size-1

while(left <= right){                                            //保证区间合理

        middle = (left + right)/2

        if(nums[middle] > target){

                right = middle -1                                //已经保证不包含middle了

                }

        elseif(nums[middle] < targrt){

                left = middle + 1                               //已经保证不包含middle了

        else{

                return middle

        }

        return -1;

}

代码:

// 版本一
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;
    }
};

 左闭右开——[left,right)

left = 0

right = num_size-1

while(left < right){                                            //保证区间合理

        middle = (left + right)/2

        if(nums[middle] > target){

                right = middle                                     //由于右开,所以right直接 = middle没问题

                }

        elseif(nums[middle] < targrt){

                left = middle + 1                               //由于左闭,所以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(); // 定义target在左闭右开的区间里,即:[left, right)
        while (left < right) { // 因为left == right的时候,在[left, right)是无效的空间,所以使用 <
            int middle = left + ((right - left) >> 1);
            if (nums[middle] > target) {
                right = middle; // target 在左区间,在[left, middle)中
            } else if (nums[middle] < target) {
                left = middle + 1; // target 在右区间,在[middle + 1, right)中
            } else { // nums[middle] == target
                return middle; // 数组中找到目标值,直接返回下标
            }
        }
        // 未找到目标值
        return -1;
    }
};

时间复杂度:O(logn)

空间复杂度:O(1)

讨论点

  1. 二分的几种情况,l=0,r=n时,while(l<r)是正确的写法,而当r = n-1时,while(l<=r)是正确写法
  2. 二分的本质:根据是否满足题目的条件来缩小答案所在的区间
  3. 二分的前提:有序数组
  4. 最大的优势:时间复杂度为O(logn),看到有序数组需要反应是否可以使用二分
  5. 二分mid溢出的问题:mid = l+(r-l)/2 or mid = l+((r-l)>>1)

Leetcode27.移除元素

删除数组中的元素,数组的连续很重要,删除元素不仅仅是删除,而是覆盖

数组的erase函数是O(n)的一个操作

暴力实现

时间复杂度为O(n^2)

双指针解法

快慢指针定义

  • 快指针:寻找新数组的元素,即不包含目标元素的数组
  • 慢指针:指向更新新数组下标的位置
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int slowIndex = 0;
        for (int fastIndex = 0; fastIndex < nums.size();fastIndex++){
            if (val != nums[fastIndex]){
                nums[slowIndex] = nums[fastIndex]; //将快指针指向的数传给慢指针指向的地方
                slowIndex++;

            }
        }
        return slowIndex;
    }
};

时间复杂度:O(n)

空间复杂度:O(1)

讨论点

  1. 快指针可以理解成在旧数组中找到非目标元素,然后赋值给慢指针指向的新数组
  2. fast < nums.size()正确,而fast < nums.size()-1时报错,由于后者会在空数组时报错,
    vector的size()函数返回值是无符号整数,空数组时返回0,-1得到溢出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值