代码随想录训练营第一天LeetCode704二分查找,LeetCode35,LeetCode34,LeetCode27移除元素

文章讲述了在Java中使用二分查找算法解决LeetCode题目,涉及基础版本、改动版本以及如何应用二分查找思想解决搜索插入位置、查找元素范围和移除元素问题,同时讨论了整数溢出问题的处理方法。
摘要由CSDN通过智能技术生成

代码随想录训练营第一天|LeetCode704二分查找,LeetCode35,LeetCode34,LeetCode27移除元素

题目链接704二分查找

思路1:二分查找基础版


    /**
     * 二分查找基础版
     * @param a 待查找的数组
     * @param target 待查找的目标值
     * @return 找到则返回索引,找不到返回-1
     */
    public static int binarySearch(int[] a, int target){
        int i = 0, j = a.length - 1;    //设置指针和初值
        while (i <= j){                 //i~j范围内有东西
            int m = (i + j) >>> 1;
            if(target < a[m]){          //目标在左边
                j = m - 1;
            }else if(a[m] < target){    //目标在右边
                i = m + 1;
            }else{                      //找到了
                return m;
            }
        }
        return -1;
    }
  • 问题1:为什么是i <= j意味着区间内有未比较的元素,而不是i < j?
    答:因为i = j它们指向的元素也会参与比较,如果是i < j的话就会漏掉最后一次比较,
    导致最终找不到元素。
  • 问题2:(i+j)/2有没有问题?
    答:当i和j比较大时相加超过了Java中整数的表示范围就会溢出变成负数,这是因为Java中
    采用补码表示法来存储整数,把最高位视为符号位,正数的二进制表示与其原码相同,而
    负数的补码是其原码取反然后加1。而采用无符号右移一位的形式(i+j)>>>1也可以达到
    (i+j)/2的效果,无符号右移不考虑符号位,空缺的位用0填充,这样就不会因为符号位
    的影响而导致负数的右移结果仍然为负数。
  • 问题3:都写成小于号有啥好处?
    答:因为数组是升序排列,这样可以和人类思维习惯保持一致。

思路2:二分查找改变版

 /**
     * 二分查找改动版
     * @param a 待查找的数组
     * @param target 待查找的目标值
     * @return 找到则返回索引,找不到返回-1
     */
    public static int binarySearchAlternative(int[] a, int target){
        int i = 0, j = a.length;    //第一处
        while (i < j){                 //第二处
            int m = (i + j) >>> 1;
            if(target < a[m]){
                j = m;                  //第三处
            }else if(a[m] < target){
                i = m + 1;
            }else{
                return m;
            }
        }
        return -1;
    }
  • 第一处和第三处改动是因为只把j当作边界,其指向的一定不是查找元素,而第二处当i=j时,若查找数组内没有
    的元素时,会陷入一个死循环。

题目链接35搜索插入位置

思路:要理解谁是插入位置,用二分查找基础版代码改写,找到返回 m,没找到 i 代表插入点

public int searchInsert(int[] a, int target) {
    int i = 0, j = a.length - 1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            return m;
        }
    }
    return i; // 原始 return -1
}

题目链接34在排序数组中查找元素的第一个位置和最后一个位置

思路:利用二分查找中的leftmost和rightmost方法,分别用方法找到第一个元素和最后一个元素,然后再合并

	//返回重复元素中的最左侧元素
    public int leftMost(int[] nums, int target){
        int i  = 0, j = nums.length - 1;
        int candidate = -1;
        while(i <= j){
            int m = (i + j) >>> 1;
            if(target < nums[m]){
                j = m - 1;
            }else if(nums[m] < target){
                i = m + 1;
            }else{
                candidate = m;
                j = m - 1;
            }
        }
        return candidate;
    }

    //返回重复元素中的最右侧元素
    public int rightMost(int[] nums, int target){
        int i  = 0, j = nums.length - 1;
        int candidate = -1;
        while(i <= j){
            int m = (i + j) >>> 1;
            if(target < nums[m]){
                j = m - 1;
            }else if(nums[m] < target){
                i = m + 1;
            }else{
                candidate = m;
                i = m + 1;
            }
        }
        return candidate;
    }

  public int[] searchRange(int[] nums, int target) {
        int x = leftMost(nums, target);
        if(x == -1){
            return new int[]{-1,-1};
        }else{
            return new int[]{x,rightMost(nums, target)};
        }

    }


题目链接27移除元素

思路一:暴力求解,外层循环遍历位置,如果找到与查找元素相等,再使用内层循环将查找元素之后的元素前移,覆盖掉所查找元素。

 public int removeElement(int[] nums, int val) {
        int length = nums.length;
        for(int i = 0; i < length; i++){
            if(nums[i] == val){
                for(int j = i + 1; j < length; j++){
                    nums[j-1] = nums[j];
                }
                i--;
                length--;
            }
        }
    return length;
    }

思路二:双指针法,定义一个fast指针,代表新数组所需要的元素,再定义一个slow指针,代表新数组下标位置,如果新数组里的元素不等于所查找的值,则将元素赋给新数组下标位置,慢指针自增。

 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;
    }
  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值