代码随想录算法训练营第一天 |LeetCode704. 二分查找、LeetCode35.搜索插入位置、Leetcode27. 移除元素

代码随想录算法训练营

Day1 代码随想录算法训练营第一天 |LeetCode704. 二分查找、LeetCode35.搜索插入位置、Leetcode27. 移除元素



前言

备战期末工科数学分析刷题打卡
今天是算法训练营第一天,主要学习的是二分查找和快慢指针

LeetCode704

讲解文档
视频讲解

LeetCode27

讲解文档
视频讲解


一、LeetCode704. 二分查找

题目链接:LeetCode704

1.基础

(1)二分查找的条件:有序数组
(2)二分查找的时间复杂度 o(logn)

2.二分查找的两种写法

左闭右闭区间[l,r]左闭右开区间[l,r)
遍历边界l<=rl<r
遍历边界的解释当l=r时,区间[l,r]有意义,还可以继续求mid在l=r时,区间[l,r]无意义,不可以继续求mid
r和l的更新l=mid+1,r=mid-1l==mid+1,r=mid
r和l的更新的解释无论nums[mid]>target还是nums[mid]<target,mid对应的值都不是我们要找的目标,不该出现在备选区间nums[mid]>target或者nums[mid]<target,mid不该出现在备选区间,但是备选区间不包含r,所以mid为r是可以的

3.二分搜索

在了解二分查找的本质后,我们用同样的办法确定二分搜索问题的边界和更新方式

3.题解

(个人喜欢左闭右闭区间,暂时就写了这一种(/ω\))

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

二、LeetCode35.搜索插入位置

1.我的题解

class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int l = 0;
        int n = nums.size();
        int r = n - 1;
        int res;
        int mid;
        while (l < r) {
            mid = (l + r) / 2;
            if (nums[mid] > target) {
                r = mid - 1;
            } else if (nums[mid] < target) {
                l = mid + 1;
            } else {
                l = mid;
                r = mid;
                break;
            }
        }

        if (nums[l] < target) {
            return l + 1;
        } else {
            return l;
        }
    }
};

2.想法

(1)查找方式:

题目要求时间复杂度o(logn),所以用二分查找(我在这里用的是左闭右闭区间写法)

(2)哪里和模板不一样:

现在我们不是要找到和target 相等的元素,我们要找插入位置,不一定有和target相等的元素

(3)初步判定有两种主要情况

1)存在和target相等的元素:

target插在这个和他相等的元素所在的位置,也就是一开始和他相等的元素及其后边的元素应当向右移动
这个时候可以break出来,在外面return。
为什么把l,r赋值成mid:这种情况下不能确定l=mid,为了统一循环后面的返回部分所以这样写
(一开始这里出错了)

2)不存在和target相等的元素:

r与l不断接近,达到相等,最后退出循环。如果要确定target插入位置,应该在l=r时确定,所以循环边界设定为l<r,这样在l=r时可以退出循环,进入插入位置的判别。
l=r时可以分为两种,若target大于此时nums[l],则插在l+1的位置;若target小于此时nums[l],则插在l的位置,相当于nums[l+1]元素及其后边的元素应当向右移动

三、Leetcode27. 移除元素

1.快慢指针法

快指针i:负责遍历原数组,判断元素与val是否一致
慢指针j:负责遍历新数组,指向新数组最新的一个元素

2.想法

(1)快指针i负责遍历原数组,判断元素与val是否一致

如果一致,则更新快指针而慢指针不动;
如果一致,则慢指针指向这个元素(nums[j]=nums[i]),更新快指针和慢指针

(2)节约空间

新数组仍然利用nums的空间,快指针找到不同于val的元素后,慢指针将他保存到新的nums里,覆盖掉原来的val,依次存放,确保顺序不变

为什么可行:判题时只看前k个元素,确保前k个元素是不含val的,按照原顺序排列的即可

3我的题解

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int n = nums.size();

        int j = 0;
        for (int i = 0; i < n; i++) {
            if (nums[i] != val) {
                nums[j] = nums[i];
                j++;
            }
        }
        return j++;
    }
};

4曾经的做法

这种做法是先从先向后遍历,如果遇到等于val的元素,就从这一点开始将后一个元素赋给前一个元素(整体向左移动)。
元素前移:这是数组删除元素的一般方法,但是在这里其实没有必要这样做。

class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int n=nums.size();
        int i=0;
        while(i<n){
        	if(nums[i]!=val){
              i++;
              continue;
           }
         else{
             for(int k=i;k<=n-2;k++){
                  nums[k]=nums[k+1];
               }
            n--;
           }
       }
            return n;
    }
};

总结

今天是算法训练营第一天,主要学习的是二分查找和快慢指针
快慢指针一些更重要的用途可能明天会做。
希望这个暑假算法水平能有进步(╹▽╹)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值