代码随想录算法训练营第一天 | ( Part 1 ) 704. 二分查找

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

704. 二分查找

题目链接:https://leetcode.cn/problems/binary-search/

文档链接:https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html (源于代码随想录)

可以参考视频讲解:https://www.bilibili.com/video/BV1fA4y1o715 (源于代码随想录)

思路:

处理对象 为 数组 , 且 有序 ,

数组 可以 随机访问 , 访问 某一确认位置 的 时间复杂度 为 O(1)

对于 有序 的 线性表 ,与 中间 的 值 进行 比较,一次 可以 排除掉 一半的数据 (/直接 找到 目标)

相对于在数组 中 一个一个 找 效率 有了 很大 的 提升

 

整体查找 的 时间复杂度 为 log(n)

 

易错点 和 需要注意的点:

  1. target 和 mid点 在 写代码时 容易 下意识 搞混了

  2. 选择左侧区间时 注意 调整右边界 , 选择右侧区间时 注意 调整左边界

  3. 注意 不要忘了 更新 mid 点 的值

 

实现时 的 思路:

  1. 使用 C++ STL标准库 中 的 begin() 、end()、获取 相对于 数据类型 的 逻辑 下标 , 进而获取数组的长度

  2. 根据 比较 的 情况( 等于 / 小于 / 大于 ) ,提交 结果 下标 / 选择 左 右区间 ,

    (如果 思考 相对 负载 太大 , 可以 将 内容 划分 , 先 从小块的内容 开始 思考/处理 ,逐渐 削弱 ,/ “蚕食” 问题 )

  3. 在 求 mid 值 时 ,注意 防溢出 , “使用减法 配合 ,削减 中间结果 可能出现 的 最大值”

    mid = left + ( right - left ) / 2 ;

  4. “递归 逻辑” 运行 到 left 或 right 越过 对方 后

    (实际上 是 非递归 实现)

  5. 当 left == right 时 , 还有 最后 一个 元素 进行 比较 (在 虚拟渲染 运行 过程 时 可以 先从 一些 特殊/特征 点 思考 起 )

 

代码 实现:

int search(vector<int>& nums, int target) {
   int len = end(nums) - begin(nums);

   int left = 0;
   int right = (len - 1);

   int mid =   left  + (right - left)/2;         //int mid = (left + right)/2;

   while(left<=right){
                                           
       if(target==nums[mid])
      {
           return mid;
      }else
       if(target<nums[mid])                //target 、 mums[mid] 在思考时 易 混晞
      {
           right = mid - 1;                //注意 “选左区间 改 右边界 ,选右区间 改 左边界 ”

      }else
       if(target>nums[mid])
      {
           left = mid + 1;
      }
       mid =   left + (right - left)/2;                             // 易漏
  }

   return -1;

}

 

 

 

27. 移除元素

题目链接:https://leetcode.cn/problems/remove-element/

文档链接:https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html(源于代码随想录)

可以参考视频讲解:https://www.bilibili.com/video/BV12A4y1Z7LP (源于代码随想录)

思路:

基础实现思路: (这次是暴力解)

顺着数组进行扫描,将所有符合要求的元素删除,(删除 操作 : 将 后边 的 有效元素 前移 (1 个 位置))

将 “删除 操作” 提取 分离 ,单独 进行 实现 , 以 简化 程序 结构

 

暴力解:

int removeElement(vector<int>& nums, int val) {
       int len = end(nums) - begin(nums);
       
       int count = 0;

       int i = 0;

       //注意 预防 溢出

   
   
       //while((i<(len-count))&&(i<len))

       //分情况 分析                             如 // 在更早循环删除的 / 在前一次循环删除的

       while((i<(len-count)))
      {
           //重要 , 关键 的 内循环
           if(nums[i] == val)
          {
               
               moveLeft_1_FromRange(nums, (i+1) , (len - 1 - count));

               count++;

          }
           else            //xx 位置 的 信息 更新了 , 需要 重新 判断
          {
               i++;

          }

           
      }


       return (len - count);

  }

   void moveLeft_1_FromRange(vector<int>& nums, int left , int right)
  {
       int i = left - 1;

       for(;i < right ; i++)
      {
           nums[i] = nums[i+1];

      }


  }

 

思路 —— 双指针 法:

双指针法,简单来说,就是 准备 一个指针,来将 整个 数组 的 元素 进行扫描,然后再准备一个指针 来接收 要存留下来的元素。

 

 

这次 数组 修改的频率 比较高,时间量级 到了 O(n)

但其实如果你 不这么做, 按照 ( 将 删除元素 后边 的 元素 全部 前移 ) 的 方法 进行 , 修改 的 频率 更高 , 能 达到 O(n²)

 

这里 是 “有舍才有得” ,“用 ‘记录 需要保留 元素’ 的 代价 ,简化 元素 位置 的 调整,来换取 整个操作 修改频率 的 降低”

 

推广一下,双指针也可以,推广到多指针,

可以为 每一个 分支任务 分配一个 指针 进行 支持,以使 我们的程序 更具有 操作性 ,

为 程序 以后的 发展 奠基 , 使 长远 的 发展 成为 可能

 

 

双指针 法:

int removeElement(vector<int>& nums, int val) {
       int len = end(nums) - begin(nums);
       
       int count = 0;

       int j = 0;

       int i = 0;

       //     易 写 成 while(j < (len - count))       //这回 j 指针 要 “运行 到 头”
       while(j < len )
      {
       
           if(nums[j]==val)
          {
               j++;

               count++;

          }
           else        // nums[j]!=val
          {
               nums[i] = nums[j];

               i++;
               j++;
                           //修改 元素 的 频率 有点 高 , 但 如果 对 要删除的元素 后边 的 元素 进行 依次 顺移 , 修改 的 频率/量   更高
          }

      }

       return (len - count);
  }
 

 

posted @   晴夜空  阅读(46)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示