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

第一章 数组part01

题目:704. 二分查找,27. 移除元素

参考链接:代码随想录

704.二分查找

关键点:边界点写法容易把握不好 ,到底是小于还是小于等于?等于middle还是 等于middle-1?

一般常见的写法有:左闭右闭和左闭右开

思路:使用left,right指针分别指向数组开始和结尾,然后每次循环计算middle,将mid和target比较,直到不满足left<right,返回-1。注意下标的开闭区间不同写法。

class Solution {//(版本一)左闭右闭区间
    public int search(int[] nums, int target) {
        //避免当target小于nums[0],num[nums.length -1]时多次循环运算
        if(target < nums[0] || target > nums[nums.length - 1]){
            return -1;
        }
        int left =0,right = nums.length - 1;
        while(left <= right){
            int middle = (left + right)/2;
            //mid = left + ((right - left) >> 1); 移位操作?
            if(nums[middle] == target)
                return middle; 
            else if(nums[middle] > target)
                right = middle -1;
            else if(nums[middle] < target)
                left = middle +1;
        }
        return -1;
    }
}
class Solution {//(版本二)左闭右开区间
    public int search(int[] nums, int target) {
        int left = 0,right = nums.length;
        while(left < right){
            int middle = left + ((right - left) >> 1);
            if(nums[middle] == target )
                return middle;
            else if(nums[middle] > target)
                right = middle;
            else if(nums[middle]  < target)
                left = middle + 1;
        }
        return -1;
    }
}

补充说明:

①避免当target小于nums[0],nums[nums.length - 1]时多次运算,这部分开始没想到,思路不全面,标记一下。

if(target < nums[0] || target > nums[nums.length - 1]){
            return -1;

②mid = left + ((right - left) >> 1); 移位操作?

这里采用了 >> 来获得区间的中点下标,学习一下该写法。

>>:右移,m>>n 代表 m除2的n次方(常用m >> 1,即m/2)

<<:左移,m<<n 代表 m 乘2的n次方 

27.移除元素

思路:有的同学可能说了,多余的元素,删掉不就得了。

要知道数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖。

暴力解法

这个题目暴力的解法就是两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。 很明显暴力解法的时间复杂度是O(n^2),这道题目暴力解法在leetcode上是可以过的。

  • 时间复杂度:O(n^2)
  • 空间复杂度:O(1) 

class Solution {//方法一:暴力解法
    public int removeElement(int[] nums, int val) {
        int size = nums.length;
        for(int i = 0; i < size ; i ++){
            if(nums[i] == val){
                //发现需要移除的元素,就将数组集体向前移动一位
                for(int j = i + 1; j < size; j++){
                    nums[j - 1] = nums[j];
                }
                i--;//因为下标i以后的数值都向前移动了一位,所以i也向前移动一位
                size--;//此时 数组的大小-1
            }
        }
        return size;
    }

}
双指针法:

双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。

定义快慢指针

  • 快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
  • 慢指针:指向更新 新数组下标的位置

很多同学这道题目做的很懵,就是不理解 快慢指针究竟都是什么含义,所以一定要明确含义,后面的思路就更容易理解了。

快慢双指针法 : 

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;
    }
}

 相向双指针法 :

//相向双指针法
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        while(right >= 0 && nums[right] == val) right--; //将right移到从右数第一个值不为val的位置
        while(left <= right) {
            if(nums[left] == val) { //left位置的元素需要移除
                //将right位置的元素移到left(覆盖),right位置移除
                nums[left] = nums[right];
                right--;
            }
            left++;
            while(right >= 0 && nums[right] == val) right--;
        }
        return left;
    }
}

  相向双指针法 (版本二):

// 相向双指针法(版本二)
class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        while(left <= right){
            if(nums[left] == val){
                nums[left] = nums[right];
                right--;
            }else {
                // 这里兼容了right指针指向的值与val相等的情况
                left++;
            }
        }
        return left;
    }
}

总结

  • 二分查找注意边界问题,通过最开始定义的搜索区间来确定判断条件和更新区间。
  • 数组中删除元素实际为覆盖元素,使用双指针解题时要明确两个指针指向的意义和移动过程。
  • 9
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值