代码随想录算法训练营第一天| 704. 二分查找、27. 移除元素。

本文详细解析了二分查找算法的实现思路,包括左闭右闭和左闭右开两种区间取值方式,并对比了它们的时间和空间复杂度。同时介绍了数组中移除元素的两种方法:暴力破解和双指针优化,以及C++代码示例。

704.二分查找

文档讲解:代码随想录

视频讲解:手把手带你撕出正确的二分法 | 二分查找法 | 二分搜索法 | LeetCode:704. 二分查找_哔哩哔哩_bilibili

题目链接:. - 力扣(LeetCode)

 解题思路:

         二分查找方法不必赘述,用代码实现的思路为:创建left、right和middle的变量,初始值分别为数组最左边和最右边的下标,middle的值为left加right的一半(middle也是下标)。后续while循环条件是left与right的大小判断,循环内容为需要查找的值target和数组中middle下标对应的值的大小判断。

  • 时间复杂度:O(log n)。每次循环查找时间减半,因此log n
  • 空间复杂度:O(1)

 关键点:

        1.在最开始时需要设定好查找区间取值范围形式,在循环中每次取半后的区间取值形式要和最开始统一。有[left,right]、[left,right)和(left,right]三种,分别对应左闭右闭,左闭右开和左开右闭。其中左开右闭写法不常见。(个人见解:统一取值范围形式与否不会影响解题,而主要是便于理清代码思路,如果最开始是左闭右闭区间形式,后续却是左闭右开形式,这样不方便理解代码。)

        2.不同的区间取值范围形式,对应的初始下标、while循环判断条件和赋值操作都略有不同。

c++代码:

1.左闭右闭写法

class Solution 
{
public:
    int search(vector<int>& nums, int target) 
    {   //左闭右闭写法
        int left = 0;//左边起始下标
        int right = nums.size() - 1; //右边起始下标
        int middle;
        //开始循环进行二分查找
        while(left <= right)
        {   
            middle = (left + right) / 2;
            if(nums[middle] > target)
            {
                right = middle - 1;
            }
            else if(nums[middle] < target)
            {
                left = middle + 1;
            }
            else
            {
                return middle;
            }
        }
        
        return -1;
    }
};

对左闭右闭写法区间重新取值的个人见解:左闭右闭写法中,right和left的取值是等于middle还是middle加减1都可以,让left、right取值等于middle是偷懒的写法但在数学逻辑上不严谨,存在对重复元素的判断。

2.左闭右开写法

         两种写法不同之处在注释中提及。

class Solution 
{
public:
    int search(vector<int>& nums, int target) 
    {   //左闭右开写法
        int left = 0;
        int right = nums.size(); //右边起始下标初始值不同,是数组大小而非数组大小减1
        int middle;
       
        while(left < right) //循环条件不同,为小于而非小于等于
        {   
            middle = (left + right) / 2;
            if(nums[middle] > target)
            {
                right = middle; //right赋值为middle而非middle-1
            }
            else if(nums[middle] < target)
            {
                left = middle + 1;
            }
            else
            {
                return middle;
            }
        }
        
        return -1;
    }
};

27.移除元素

文档讲解:代码随想录

视频讲解:数组中移除元素并不容易! | LeetCode:27. 移除元素_哔哩哔哩_bilibili

题目链接:. - 力扣(LeetCode)

解题思路: 

1.双重for循环暴力破解。一层for循环遍历数组查找需要删除的值,第二层for循环更新数组。(本文暂不继续说明此方法)

  • 时间复杂度:O(n^2)。双重循环,故n^2
  • 空间复杂度:O(1)

2.双指针。定义快指针fast和慢指针slow,快指针fast从0开始遍历数组寻找不需要删除的值,慢指针slow从0开始更新数组生成删除指定元素后的新数组。

  • 时间复杂度:O(n)。一层循环,执行时间t与输入n呈线性关系,故n
  • 空间复杂度:O(1)

关键点:

1.对数组的理解。数组在定义后在内存中大小是固定不变的,所谓的删除操作都是覆盖操作。不同的编程语言会对数组进行封装,如c++中的erase方法删除元素并自动使数组size减少,其本质还是覆盖操作并改变计数器的值。

c++代码:

1.整形形式快指针慢指针。

class Solution 
{
public:
    int removeElement(vector<int>& nums, int val) 
    {
          int fast = 0; //  快指针
          int slow = 0; //  慢指针
          for(fast;fast < nums.size();fast++)
          {
              if(nums[fast] != val)
              {
                  nums[slow] = nums[fast];
                  slow++;
              }
          }
            return slow;
    }
};

2.指针形式快指针慢指针

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值