Day01| 27. 移除元素、704. 二分查找

文章介绍了两种解决移除数组元素的方法:暴力解法(时间复杂度O(n^2))和双指针法(时间复杂度O(n)),并提供了对应的Java实现。此外,还详细讲解了二分查找的基本模板,包括标准二分查找、查找左边界和查找右边界的情况。
摘要由CSDN通过智能技术生成

Day01| 27. 移除元素、704. 二分查找

27. 移除元素

在这里插入图片描述解法1: 暴力解法(两层for循环,一个for循环遍历数组元素 ,第二个for循环更新数组。)

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

解法2:双指针法
双指针法(快慢指针法): 通过一个快指针和慢指针在一个for循环下完成两个for循环的工作。
定义快慢指针:
快指针:寻找新数组的元素 ,新数组就是不含有目标元素的数组
慢指针:指向更新 新数组下标的位置
看代码,相当于就是只有在nums[fast]!=val时,才会给nums[slow]赋值;只有slow处得到了赋值,才能前进(i.e. slow++)。

// 双指针法
// 时间复杂度:O(n)
// 空间复杂度:O(1)
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];
                slow++;
            }
        }
        return slow;
        
    }
}

补充:还有一个相向双指针法:

//相向双指针法
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;
    }
}

704. 二分查找

704题考察的就是标准的二分查找。用三个模板中的第一个即可。
如下,是按照左闭右闭的方式总结的3个二分查找模板。第1个就是标准的二分查找,第2个是查找左边界(即待查找元素第1次出现的索引),第3个是查找右边界(即待查找元素最后1次出现的索引)。
必须背下来!

int binary_search(int[] nums, int target) {
    int left = 0, right = nums.length - 1; 
    while(left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1; 
        } else if(nums[mid] == target) {
            // 直接返回
            return mid;
        }
    }
    // 直接返回
    return -1;
}


int left_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 别返回,锁定左侧边界
            right = mid - 1;
        }
    }
    // 判断 target 是否存在于 nums 中
    // 此时 target 比所有数都大,返回 -1
    if (left == nums.length) return -1;
    // 判断一下 nums[left] 是不是 target
    return nums[left] == target ? left : -1;
}


int right_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            left = mid + 1;
        } else if (nums[mid] > target) {
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 别返回,锁定右侧边界
            left = mid + 1;
        }
    }
    // 此时 left - 1 索引越界  right=left-1 
    if (right < 0) return -1;
    // 判断一下 nums[left] 是不是 target
    return nums[right] == target ? (left - 1) : -1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值