LeetCode:704.二分法查找 and 27.移除元素

文章介绍了两种基于二分法的查找算法,用于在有序数组中寻找目标值,分别讨论了左闭右闭和左闭右开的情况,以及两种不同的移除元素的方法,包括快慢指针法和首尾双指针法,所有方法均要求在O(1)额外空间内完成,并提供了相应的时间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

704.二分法查找

前提条件

  • 使用二分法查找,需要提前将数组排序
  • 可使用Arrays.sort(数组名);对数组进行排序
  • 数组中没有重复的元素

题目

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/binary-search

过程:

  • 设定左指针(left),右指针(right) 和 中间指针(middle)
  • 定位中间位置(left + (right - left) / 2),并判断 下标值 == target
    nums[middle] == target 则返回该位置下标
    nums[middle] > target 则右侧指针移到中间
    nums[middle] < target 则左侧指针移到中间

解法一(左闭右闭,left <= right)

  • 时间复杂度:O(logN)
  • 空间复杂度:O(1)
class Solution {
    public int search(int[] nums, int target) {
        if(nums == null || nums.length == 0) return -1;
        // 避免多次循环运算
        if(target > nums[nums.length - 1] || target < nums[0]) return -1;
		//左指针
        int left = 0;
        //右指针
        //数组长度减1才能定位到数组末尾下标的位置上
        int right = nums.length - 1;
        //循环,定义target在 [left, right] 左闭右闭的区间
        while(left <= right){
            //防止溢出,用(left + right) / 2会有溢出的现象
            int middle = left + (right - left) / 2;
            //判定target值的大小,定义值位置
            if(target < nums[middle]){
                //target在左区间 [left, middle - 1]
                right = middle - 1;
            }else if(target > nums[middle]){
                //target在右区间 [middle - 1, right]
                left = middle + 1;
            }else{
                //target == nums[middle],输出下标值
                return middle;
            }
        }
        //target不再数组nums[]范围内,输出-1
        return -1;
    }
}

解法二(左闭右开,left < right)

  • 时间复杂度:O(logN)
  • 空间复杂度:O(1)
class Solution {
    public int search(int[] nums, int target) {
        //左指针
        int left = 0;
        //右指针
        //数组长度减1才能定位到数组末尾下标的位置上
        int right = nums.length;
        //循环,定义target在 [left, right) 左闭右开的区间
        //当left == right 时,[left, right)时无效区间
        while(left < right){
            //防止溢出,用(left + right) / 2会有溢出的现象
            int middle = left + (right - left) / 2;
            //判定target值的大小,定义值位置
            if(target < nums[middle]){
                //target在左区间 [left, middle)
                right = middle;
            }else if(target > nums[middle]){
                //target在右区间 [middle + 1, right)
                left = middle + 1;
            }else{
                //target == nums[middle],输出下标值
                return middle;
            }
        }
        //target不再数组nums[]范围内,输出-1
        return -1;
    }
}

27.移除元素

题目

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
在这里插入图片描述
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-element

快慢指针法(双指针法)

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
class Solution {
    public int removeElement(int nums[], int val) {
        //慢指针
        int slow = 0;
        //快指针(fast),循环
        for(int fast = 0; fast < nums.length; fast++){
            //判断,val不等于nums[fast]时,将nums[fast]值传入到slow数组中
            if(val != nums[fast]){
                //slow++,将slow下一个下标位置腾出来
                nums[slow++] = nums[fast];
                
                //可以将nums[slow++]拆分
                //nums[slow] = nums[fast];
                //slow++;
            }
        }
        return slow;
    } 
}

首尾双指针法

class Solution {
    public int removeElement(int[] nums, int val) {
        int left = 0;
        int right = nums.length - 1;
        // 让right从尾找到数值不为val的第一个元素
        while(right >= 0 && nums[right] == val) right--;
        while(left <= right){
            if(nums[left] == val){
                nums[left] = nums[right];
                right--;
            }
            left++;
            // 在将不为val的值赋给left之后,继续寻找下一个不为val的元素
            while(right >= 0 && nums[right] == val) right--;
        }
        return left;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值