代码随想录算法训练营 day01

目录

数组理论基础

704.二分查找

闭区间 |解题思路

正解:

左闭右开区

间 |解题思路

正解:

27.移除元素

---暴力解法---

第一版:测试失败

第二版:测试失败

第三版:测试失败

正解:

---快慢指针---

正解


数组理论基础

概念:数组是存放在连续内存空间上的相同的数据类型的集合

704.二分查找

力扣题目给定的条件是 升序,元素不重复,元素为整数

最开始看到这个题目,我的想法 : 二分法,那肯定要从中间分哦,那就需要知道数组长度,然后除二,目标值与中间值比较大小,比完了就能确定左还是右,再然后我就不知道如何处理了.卡住了

大一下学的数据结构与算法,现在都忘得差不多了,因为觉得难,就没有好好复习过.只是应付了期末考试

我只有看看文章,来理清思路:解题方法有两种---闭区间和左闭右开区间

闭区间 |解题思路

1 while条件怎么确定

可以确定的是left < right 但是时候加上等于符号,还要看使用哪种题解方法.

闭区间的话,就要加上等于符号,因为如文章所示,假设我要查找的目标值是第一个,那就会产生left=right的情况,这样才可以找到目标值,反之第二种解题方法,不需要它们相等,就可以找到.

2 如何定区间?

left=0,必须初始化,不然走到while循环就要报错:变量可能没有初始化~

right确定为数组最后一个元素的下标

middle确定为left+((right-left)/2),而不是right/2(这是我最开始的想法),原因:当目标值大于中间值,那么闭区间中的左下标就会发生变化,left=middle+1; 再次改变middle的值,如果还是right/2,那么就会造成下标溢出的问题,所以不能这样写.

边界值和中间值的问题解决了,就可以在while循环中写if语句了,要么左,要么右,要么就是 return middle;

3 如何优化代码?

文章说的是在进入循环判断之前,就写一条语句判断目标值是否在该数组中,不在就返回-1,这样能减少无意义的循环次数,减少内存消耗.

正解:

class Solution {
    public int search(int[] nums, int target) {
    if(target <nums[0] || target>nums[nums.length-1]){
         return -1;
     }
     int middle=0,left=0,right=0;//int基本数据类型  默认值是0,但是还是必须初始化,不然走到while循环就会报错
     right=nums.length-1;
     while(left<=right){
       // middle=right/2; 为什么不能这样写,因为你想看
       //目标值可能在右区间,所以左下标就会发生变化,而此时中间下标也会移动到左下标右边
       //单纯地这样写,会造成下标溢出
       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;
    }
}

左闭右开区

间 |解题思路

当目标值在左区间,开区间的边界值right 不会作为下标,被放在数组中作比较,所以right=middle

当目标值在右区间,处理left=middle+1;同样的开区间的边界值right 不会作为下标,被放在数组中作比较

middle的处理方法同上,优化代码也是同上.

正解:

class Solution {
    public int search(int[] nums, int target) {
        if(target<nums[0] || target >nums[nums.length-1])
        {return -1;}
      int left=0,right,middle;
      right=nums.length;
      while(left<right){
          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循环,而且还试想过用增强for循环,但是发现不对劲,就没写.但是写嵌套循环,一开始我还是没有明确的思路,还是参考了文章才写的.

---暴力解法---

第一版:测试失败

class Solution {
    public int removeElement(int[] nums, int val) {
       for(int i=0; i<nums.length;i++){
           if(nums[i]==val){
                for(int j=i; j<nums.length;j++){
                    nums[j]=nums[++j];//这里
                }
           }
       }
       return nums.length;
    }
}

原因:我没考虑到下标越界,考虑不全.报错了才发现,这么写,在内层第二轮循环就会出问题;然后我就去参考了文章,接下来出现了第二个问题

第二版:测试失败

class Solution {
    public int removeElement(int[] nums, int val) {
       for(int i=0; i<nums.length;i++){
           if(nums[i]==val){
                for(int j=i+1; j<nums.length;j++){
                    nums[j-1]=nums[j];
                }
           }
       }
       return nums.length;
    }
}

原因:没考虑到nums[i+1]==val这种情况,我这样写代码就会造成本来还有需要移除的元素,但是i跑了,不管了.所以当数组移除了一个目标值,应该保证下标还在原来的位置,这样等下一轮if判断,就可以知道是否存在nums[i+1]==val这种情况了.

第三版:测试失败

class Solution {
    public int removeElement(int[] nums, int val) {
        int nLength=nums.length;
       for(int i=0; i<nLength;i++){
           if(nums[i]==val){
                for(int j=i+1; j<nLength;j++){
                    nums[j-1]=nums[j];
                }
           }
            i--;
            nLength--;
       }
       return nLength;
    }
}

原因:这个时候虽然写了第二版没考虑的代码,但是位置放错了,我当时不懂,没反应过了,我只是觉得写在if外面一样的执行啊,凭什么不可以啊,等我写好备注后,才明白,肯定不可以啊,这两句代码是要满足有元素被移除才执行,反之不动,我要是一直让下标前移,那就是毫无意义的,而且无法通过测试.

正解:

class Solution {
    public int removeElement(int[] nums, int val) {
        int nLength=nums.length;
       for(int i=0; i<nLength;i++){
           if(nums[i]==val){
                for(int j=i+1; j<nLength;j++){
                    nums[j-1]=nums[j];
                }
            i--;
            nLength--;
           }
        
       }
       return nLength;
    }
}

---快慢指针---

起初我不能理解为什么是当快指针不等于目标值才移动元素,反而等于时,啥也不做,只需要进行下一轮循环.我自己去写了一下,我想的那种,发现有点行不通,看着这么晚了,就参考文章写代码,还是有点不理解,就在纸上模拟了一遍过程,突然就懂了,这个快慢指针法,厉害的勒~这逻辑妙蛙种子!!!

就是:快指针负责遍历数组,找到排除了目标值的元素,慢指针负责更新 新数组的下标位置,

整个过程就是,找到要排除的元素,慢指针就不动,反之就更新下标,知道循环遍历完成,慢指针在哪里,那里就是数组的长度.

正解

class Solution {
    public int removeElement(int[] nums, int val) {
        int slowIndex=0;
        for(int fastIndex=0;fastIndex<nums.length;fastIndex++){
            if(nums[fastIndex]!=val){
                nums[slowIndex]=nums[fastIndex];
                slowIndex++;
            }
        }
        return slowIndex;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值