算法训练Day01|数组part01(LeetCode704. 二分查找、LeetCode27. 移除元素)

文章讲解
视频讲解

数组理论基础

数组是存放在连续内存空间上的相同类型数据的集合。内存上的地址空间是连续的,所以添加或删除元素的时候需要移动其他元素,覆盖原有的元素,而不能直接删除。

704. 二分查找

题目链接
二分查找的一个前提条件就是,有序且不重复的数组,在这样的数据中找到某一个满足条件的元素。二分查找的时间复杂度是O(logn)。

重点

区间的定义是循环不变量,从始至终边界的处理都要根据循环不变量。

一个特别好的讲解

  • 区间边界问题

    • 左闭右闭
      定义target在[left, right]中,循环条件就是 while (left <= right),if (nums[middle] > target) ,right值应该为middle-1。

    • 左闭右开
      定义target在[left, right)中,循环条件就是 while (left < right),if (nums[middle] > target) ,right值应该为middle。

  • middle的表示问题
    middle不能表示为(right + left) / 2,会溢出,而应该表示为left + (right - left) /2。

代码

  • 左闭右闭
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size()-1;    
        while(left<=right){
            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;
    }
};
  • 左闭右开
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int left=0;
        int right=nums.size(); //right取不到   
        while(left<right){
            int middle=left+(right-left)/2;
            if(nums[middle]>target){
                right=middle;
            }
            else if(nums[middle]<target){
                left=middle+1;
            }
            else{
                return middle;
            }
        }
        return -1;
    }
};

27. 移除元素

题目链接
数组中没有真正的删除,只有覆盖。

重点

有两种解法,最容易想到的是暴力解法,两层for循环,一层查找,一层移动后面的元素,时间复杂度O(n^2)。
但重点要掌握的是双指针的思想,即快慢指针法,快指针在前面探路,慢指针在后面接收新的数组元素,在一个for循环下完成两个for循环的工作,时间复杂度O(n)。

代码

  • 暴力解法
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int size=nums.size();
        for(int i=0;i<size;i++){//这里是size,不是nums.size()
            if(nums[i]==val){           
                for(int j=i+1;j<size;j++){
                    nums[j-1]=nums[j];//覆盖操作,注意j的边界范围     
                }
                i--;//超容易想不到
                size--;//size的位置,两个for循环都结束后再减减
            }
        }
        return size;
    }
};
  • 双指针(快慢指针)
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;//不用nums.size()了,这个slow就是新数组的大小
    }
};

之前这两道题都刷过,二刷随稍微轻松一些,但由于算法水平不好,总是在各种各样的问题上出错,甚至我清楚地记得上次也是这么错的,所以我把出过问题的地方标了注释,以后再看也是一个提醒。这是我第一次写博客,也是第一次尝试使用markdown编写文档,废了不少时间,但是很有收获。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值