刷题day1| 704.二分法 + 27.移除元素

今日任务

在这里插入图片描述

数组理论学习

  1. 数组是存放在 连续内存空间相同类型数据集合
  • 数组下标从 0开始
  • 内存空间 地址连续
  1. 由于地址空间的连续性

删除 和 添加元素【向数组中间】时,就要移动其他元素

在这里插入图片描述

数组元素是不能 直接删除的,需要 覆盖

  1. 相关操作的时间复杂度

访问元素:支持随机【索引】访问,O(1)

添加元素O(n)----需要移动其他元素的位置

删除元素O(n)

  1. c++的二维数组在地址空间也是连续的

理解:array[0] [0] 和 array[0] [1]在地址空间是连续的

相差四个字节

  1. c++中array和vector的区别
  • 相同点

                 1. 都能用下标访问元素
                 2. 都是顺序容器,采用的属性存储空间
    
  • 不同点

  1. 创建方式不同

​ ----vector无需指定大小,只需指定类型,eg:vector a

​ ----array要同时指定类型和大小,eg:array<int,3> a

  1. 内存使用不同

​ ----vector内存空间是动态可变的

​ ----array用多少就申请多少

Vector常用方法

初始化

在这里插入图片描述

添加删除

------这里的访问方式是通过迭代器

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

获取长度

在这里插入图片描述

erase()

在这里插入图片描述

在这里插入图片描述

704.二分查找

题目

在这里插入图片描述

代码实现

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 - l) / 2;   //防止溢出,也可以位运算更高效  l + r >>1
               if(nums[mid] > target) r = mid - 1;
               else if(nums[mid] < target) l = mid + 1;
               else return mid ;
           }
       
       return -1;
    }
};

2.定义:左闭右开的区间

class Solution {
public:
    int search(vector<int>& nums, int target) {
           //左闭右开的区间
           int l = 0 , r = nums.size();

           while(l < r){
               int mid = l + (r - l) / 2;   //防止溢出,也可以位运算更高效  l + r >>1
               if(nums[mid] > target) r = mid ;
               else if(nums[mid] < target) l = mid + 1;
               else return mid ;
           }
       
       return -1;
    }
};

具体理解

  1. 题目中 是有序【升序】 的数组 ,有序数组这里我们可以想到二分法

  2. 循环不变量规则

在循环中坚持 根据查找区间的定义 来做 边界处理

  1. 区间的定义

我们定义 target 在[left,right]区间内,

在这里插入图片描述

27.移除元素

题目

在这里插入图片描述

代码实现

  1. 暴力法
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
         //暴力法,for循环遍历,找到val直接for循环移位

         int size = nums.size(); //记录一个size值,在移除后可以更新size,方便返回
         for(int i = 0; i < size;i++){

             if(nums[i] == val){
                 for(int j = i + 1; j < nums.size();j++){
                     nums[j - 1] = nums[j];//将i之后的数组整体向前移一位                   
                 }
                 i--;  //举例:i = 0,被覆盖后,进入下一次for循环i++后 i= 1;但是得判断 i= 0位置,因为该值被覆盖了
                 size--;
             }
         }
         return size;
    }
};
  1. 双指针
  • 这是快慢指针,fast和slow同时在0处出发
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
       //双指针 【快慢指针】

     int slow = 0 ,fast = 0;

     for(fast = 0; fast < nums.size();fast++){
         //相当于为数组重新赋值
         //当值不为val的时候,nums[slow] = nums[fast],且slow ++ ;fast进入下一次循环
         //当值为val的时候,不进入if语句,fast直接++;进入下一次循环,跳过了所有值为val的地方
            //此时slow停在值val的地方,当fast++后不为val,直接赋值给slow
         if(nums[fast] != val){
             nums[slow++] = nums[fast];
         }
     }

     return slow;
    }
};
  • 也可以是双向指针 一个从下标0出发,一个从 nums.size() - 1出发
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
           //采用相向指针
           int l = 0 , r = nums.size() - 1;

           while(l <= r){
               
               //左边寻找值为val的下标
               while(l <= r && nums[l] != val ) {
                   l++;
                   }

               //从最右边开始,如果每一个值都为val的话,我们可以直接r--,直接跳过
               //我们要找到第一个值不为val的对前面进行覆盖
               while(l <= r && nums[r] == val) {
                   r --;
               }
               
               if(l < r){
                  nums[l++] =nums[r--];
               }
           }
           return l;
    }
};

具体理解

  1. 这道题的主要思想就是:数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖

所以,当你移除元素后,就必须移动之后元素的位置

  1. 题目说明在 原地修改我们就不能借助辅助数组

所以只有俩种办法:双重for循环 、双指针

  • 一般遇到原地修改数组、链表等都是双指针
  • 双指针个人理解有俩种,一种是快慢指针,一种是俩个指针指向不同位置【比如说将数组赋值给辅助数组、相向指针等】

今日感想

二分查找已经不知道写了多少遍了,20遍以上吧,应该

说实话真的快写吐了,觉得之前几期的一个友友说的很好,写二分就像背单词一直abandon、abandon,哈哈哈哈

希望进入这个刷题营能改变自己刷题停滞的现状;

加油!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值