算法训练 Day 1 | 数组:704. 二分查找、27. 移除元素

1. Leetcode704 二分查找(二分法)

1. 理论

代码随想录

2. 总结

一、模版(认真看看3种情况之间的关系)

  1. 左右闭区间[a, b]
    • 循环条件
      • start ≤ end 
    • 边界更新操作
      • tmp = (start + end) / 2
      • if (tmp < target) start = tmp + 1;
      • if (tmp > target) end = tmp - 1;
  2. 左闭右开:[a, b)
    • 循环条件
      • start < end (左右相等没意义)
    • 边界更新操作
      • tmp = (start + end) / 2
      • if (tmp < target) start = tmp + 1;
      • if (tmp > target) end = tmp; (开区间不需要越位)
  3. 左开右闭:(a, b](一般不考虑这种情况,前两种已经足够)
    • 循环条件
      • start < end (左右相等没意义)
    • 边界更新操作
      • tmp = (start + end) / 2
      • if (tmp < target) start = tmp;(开区间不需要越位)
      • if (tmp > target) end = tmp - 1;

二、⭐⭐需要考虑的边界值条件

  1. 数组为空(nums: [])
  2. 指针越界(start > length - 1;end < 0)

三、其他需要考虑的点

  • 数据类型是否溢出(int → long)

四、进阶规律:结束状态时,right指针的位置有规律

例题:35. 搜索插入位置

结论:

  • ⭐在左闭右开[a, b)的情况下,结束状态时,若target < arr.length - 1(target不在最后一个),right总会在target的右侧一个元素(不管target是否存在于arr)。
    • 原因:右侧是开区间
    • 应用:用来找边界范围
    • 注意:如果right在最后一个,记得讨论不同情况
  • 左闭右闭[a, b]的情况下,结束状态时,若target < arr.length - 1(target不在最后一个),right总会在符合target的最后一个位置;若不存在target,则在target前一个最近的位置。
    • 注意:找相同元素边界的话,arr[mid] == target归到移动左指针的条件中

3. 进阶力扣题目

A. 35. 搜索插入位置

力扣https://leetcode-cn.com/problems/search-insert-position/

// 1. 左闭右闭 [a,b]
public int searchInsert(int[] nums, int target) {
        
        int left = 0;
        int right = nums.length - 1;
        int mid = 0;
        // 最终left指针会停到最近大于target的位置
        while (left <= right) {
            mid = (left + right) / 2;
            if (target == nums[mid]) {
                return mid;
            } else if (target < nums[mid]) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

// 2. 左闭右开 [a,b)

public int searchInsert(int[] nums, int target) {
        // 左闭右开
        int left = 0;
        int right = nums.length;
        int mid = 0;
        // 3个指针会停到大于等于target的位置
        while (left < right) {
            mid = (left + right) / 2;
            if (target == nums[mid]) {
                return mid;
            } else if (target < nums[mid]) {
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        // 单独处理:如果target比数组最后的数还大
        if (target > nums[nums.length - 1]) return nums.length;
        return left;
    }

B. 在排序数组中查找元素的第一个和最后一个位置

力扣https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

思路:先找左边界,后找右边界
难点:边界值分析
情况1:数组为空
情况2:指针越界

public int[] searchRange(int[] nums, int target) {
        int start = 0;
        int end = nums.length - 1;
        int[] arr = new int[2];
        arr[0] = -1;
        arr[1] = -1;
        //边界值1:如果数组为空,返回[-1,-1]
        if (nums.length == 0) return arr;

        //找左边界
        while (start <= end) {
            int tmp = (start + end) / 2;
            if (nums[tmp] < target) start = tmp + 1;
            else end = tmp - 1;
        }
        
        //边界值2:start超过边界(nums = [1],target = 2)
        //start与end汇合时值不等于target(target不存在),[-1,-1]
        if (start >= nums.length || nums[start] != target) {
            return arr;
        }
        arr[0] = start;
        
        //找右边界
        end = nums.length - 1;
        while (start <= end) {
            int tmp = (start + end) / 2;
            if (nums[tmp] <= target) start = tmp + 1;
            else end = tmp - 1;
        }
        arr[1] = end;

        return arr;
    }


69. Sqrt(x)

367. 有效的完全平方数

二刷总结:写二分法还是有点生疏,左闭右开与左闭右闭的循环条件与二分执行语句需要想一阵子才能回忆起来。

本章用时:1h

2. Leetcode27 移除元素

1. 题目链接:27. 移除元素

2. 第一想法&题解:自然想到双指针法,比较容易理解。代码如下:

// 双指针法
    public int removeElement(int[] nums, int val) {
        int left = 0;

        for (int right = 0; right < nums.length; right++) {
            if (nums[right] == val) continue;
            else {
                nums[left] = nums[right];
                left++;
            }
        }
        return left;
    }

3. 重点难点:左右指针应该遍历右指针,并且根据特定条件更新左指针

4. 用时:30min

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值