day1-704.二分查找|27. 移除元素

704.二分查找

题目链接704.二分查找

题目要求:

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

定义:二分查找,又称折半查找,是一种在有序数组中查找特定元素的算法。它的基本原理是每次将待查找区间缩小一半,直到找到目标元素为止,或者确定目标元素不存在于数组中为止。

前提条件:给定的数组必须为有序数组,并且数组中没有重复元素,一旦有重复元素,返回的下标可能不是唯一的

难点:二分查找的主要难点和易错点在于如何选择搜索区间的边界条件,在选择边界条件时,一定要坚持区间不变量的原则(绝大部分while循环的条件都要坚持这个原则)

🤔解题思路

二分查找常见的区间边界为左闭有闭 [left,right] ,和左闭右开 [left,rigth) 

💻I.左闭有闭 [left,right]

class Solution {
    public int search(int[] nums, int target) {
       //可以将边界条件带入到区间中看看是否符合 - [0,nums.length - 1]包含所有元素
       int left = 0;    //初始化区间左边界下标数组第一个元素 - 0
       int right = nums.length - 1;    //初始化区间右边界下标数组最后一个元素-nums.length - 1 
       int midle = -1;    //初始化中间值
       while(left <= right){    //退出循环的条件
           midle = (left + right) / 2;    //得到中间值
           if(target > nums[midle]){
               left = midle + 1;    //搜索区间为左闭有闭,已经确定midle不是目标元素,所以left为midle的后一个元素,才能使新的搜索区间仍然满足[left,rigth]
           }else if(target < nums[midle]){    
               right = midle - 1;    //搜索区间为左闭有闭,已经确定midle不是目标元素,所以rigth为midle的前一个元素,才能使新的搜索区间仍然满足[left,rigth]
           }else if(target == nums[midle]){
               return midle;
           }
       }
       return -1;    //退出循环说明没有找到目标元素
    }
}

图解:

①由于区间为左闭右闭 [left,right],所以 left 为数组第一个元素0,right为最后一个元素8,这样搜索区间就包含了全部待搜索元素 [0,8];

②因为①中midle<target,所以target一定在midle后面的位置,已经确定了midle(4)不会等于target(5),所以更新left为midle的后一个元素5,成为新的搜索区间 [5,8];(如果left更新为midle,则新区间 [4,8] 中midle(4)在下次查找中被重复查找了)

③因为②中midle>target,所以target一定在midle前面的位置,已经确定了midle(6)不会等于target(5),所以更新right为midle的前一个元素5,成为新的搜索区间 [5,5];(如果right更新为midle,则新区间 [5,6] 中midle(6)在下次查找中被重复查找了)

 

💻II.左闭右开 [left,rigth) 

class Solution {
    public int search(int[] nums, int target) {
       //可以将边界条件带入到区间中看看是否符合 - [0,nums.length)包含所有元素
       int left = 0;    //初始化区间左边界下标数组第一个元素 - 0
       int right = nums.length;    //初始化区间右边界下标数组最后一个元素 - nums.length
       while(left < right){    //退出循环的条件 - [left,rigth)
           int midle = (left + right) / 2;    //初始化中间值
           if(target > nums[midle]){
               left = midle + 1;    //搜索区间为左闭有开,已经确定midle不是目标元素,所以left为midle的后一个元素,才能使新的搜索区间仍然满足[left,rigth)
           }else if(target < nums[midle]){
               right = midle;    //搜索区间为左闭有闭,已经确定midle不是目标元素,所以rigth为midle,才能使新的搜索区间仍然满足[left,rigth)
           }else if(target == nums[midle]){
               return midle;
           }
       }
       return -1;    //退出循环说明没有找到目标元素

    }
}

图解:

 

①由于区间为左闭右开 [left,right),所以 left 为数组第一个元素0,right为数组的长度9,这样搜索区间就包含了全部待搜索元素 [0,9);

②因为①中midle<target,所以target一定在midle后面的位置,已经确定了midle(4)不会等于target(5),所以更新left为midle的后一个元素5,成为新的搜索区间 [5,9);(如果left更新为midle,则新区间 [4,9) 中midle(4)在下次查找中被重复查找了)

③因为②中midle>target,所以target一定在midle前面的位置,已经确定了midle(7)不会等于target(5),所以更新right为midle所在的位置7,成为新的搜索区间 [5,7);(如果right更新为midle前一个位置,则新区间 [5,6) 中midle的前一个位置6不在下次查找区间,6被漏查了)

27. 移除元素

题目链接27. 移除元素

题目要求:

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

难点:需要原地移除目标元素,不能使用额外空间

🤔解题思路

💻I.暴力破解

使用双层for循环,外层用于遍历数组元素,内层用于移除目标元素,即将目标元素后面的所有元素前移,将目标元素覆盖

class Solution {
    public int removeElement(int[] nums, int val) {
        int size = nums.length;    //数组长度
        for(int i = 0;i < size;i++){    //外层循环,得到要移除的元素val
            if(nums[i] == val){    //
                for(int j = i + 1;j < size;j++){    //内层循环,将val后面所有的向前移一位
                    nums[j - 1] = nums[j];
                }
                size--;    //数组有效长度-1,实际上数组的长度不变
                i--;    //位置为i的元素被覆盖,需要重新扫描新元素
            }
        }
        return size;    //新数组的有效长度
    }
}

💻II.双指针

 利用快慢指针,快指针用于遍历数组元素,慢指针指向有效元素待插入的位置

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;    //定义慢指针,指有效数组元素待插入的位置
        for(int fast = 0;fast < nums.length;fast++){    //快指针,扫描数组元素
            if(nums[fast] != val){    //查找有效元素(不是被移除的元素),并向前插入
                nums[slow++] = nums[fast];   
                //上面代码等价于
                //nums[slow] = nums[fast];
                //slow++;
            }
        }
        return slow;    //慢指针所在位置下标就是数组有效长度
    }
}

图解:以数组 [2,3,3,2]为例,移除值为3的元素

慢指针slow和快指针fast初始时同时指向第一个元素nums[0],slow指向待插入元素的位置,fast指向待判断元素;nums[0] != 3,将nums[fast]赋值给nums[slow],①快慢指针都向后移动;3为须删除元素,②所以slow不懂,fast后移;③同理;

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值