代码随想录第一天 -- 704 二分查找法 ,27 移除元素

本文详细介绍了二分查找法的概念,探讨了区间选择和循环条件,提供了左闭右闭和左闭右开两种解法的代码示例,并针对移除元素问题引入双指针优化算法。
摘要由CSDN通过智能技术生成

704 二分查找法

首先我们做这道题,需要确定区间。

那么何为区间呢?区间就是你要遍历的范围。

常见的区间有哪些呢?

  • 左闭右闭  [left,right]
  • 左闭右开  [left,right)

确定区间以后,我们就可以开始做题了。

根据这道题我们常见的两个问题

第一:我们如何退出循环,是 while(left < right) ,还是 while(left <= right)

第二:我们在循环中,middle 的下标是多少呢? 是 middle - 1,还是middle。

由此我们对这道题有两种解法,分别是左闭右开,左闭右闭。

代码如下(左闭右闭):

    public int search(int[] nums, int target) {
        //先确定区间,左闭右闭  [0,nums.length -1]
        int left = 0;
        int right = nums.length - 1;
        
        //这里我们解答第一个问题?
        //为什么我这里是 left <= right
        //因为我这里是左闭右闭,我的最右边的元素是可以进行遍历的
        //从而也解决了第二个问题,因为我的最右边的元素是可以遍历的
        //说明是遍历了,也就是判断了一遍,所以 mid - 1;可以不用再次判断一次 middle
        while (left <= right) {
            //确定中间下标的值
            //这一步可以优化一下,后面会讲
            int mid = (left + right) / 2;
            int midValue = nums[mid];
            
            
            if (midValue > target) {
                right = mid - 1;
            } else if (midValue < target) {
                left = mid + 1;
            } else {
                //找到了目标元素,返回下标mid
                return mid;
            }
        }
        
        //没有找到目标元素,返回 -1
        return -1;
    }

代码如下(左闭右开):

    public int search02(int[] nums, int target) {
        //确定区间,左闭右开 [0,nums.length]
        int left = 0;
        int right = nums.length;
        
        //因为我确定了区间,是左闭右开,所以我不会遍历最右边的元素
        //从而解决了 第二个问题,我的最右边元素没有进行遍历,所以需要
        //判断,所以 mid 并不 -1,而是 mid
        while (left < right) {
            //确定中间下标元素的值
            int mid = (left + right) / 2;
            int midValue = nums[mid];

            if (midValue > target) {
                right = mid;
            } else if (midValue < target) {
                left = mid + 1;
            } else {
                return mid;
            }
        }

        //在数组中,没有找到,就返回-1
        return -1;
    }

优化代码如下:

1.我们可以使用位运算的方式来更好的处理这个问题
  int mid = (left + right ) / 2;
  可以改成 int mid = (left + right ) >> 1

小总结:

遇到这道题可以套公式:

如果你是左闭右闭,就可以是 while(left <= right),边界值已经被处理了,就不要再判断了,mid - 1,或者 mid + 1。

如果你是左闭右开,就可以是 while(left < right),边界值没有被处理,就需要判断,mid 而不是 mid -1 啦。

LeetCode 27.移除元素

其实该题直接使用暴力解法也可以的,使用双层for循环即可。第一层遍历所有元素,在找到了要移除的元素后,进行第二层的遍历,也就是移除操作。将后面的元素的值依次向前覆盖元素的值即可。

代码如下(暴力解法):

    public int removeElement02(int[] arr, int val) {
        //数组的大小
        int size = arr.length;
        //第一层循环遍历数组所有的元素
        for (int i = 0; i < arr.length; i++) {
            //如果找到了该元素,就移除
            if (arr[i] == val) {
                for (int j = i + 1; j < arr.length; j++) {
                    //将后面元素的值依次覆盖原来的元素值
                    arr[j - 1] = arr[j];
                }
                //因为移除了,所有size和i都--
                i--;
                size--;
            }
        }
        //返回size的大小
        return size;
    }

但是时间复杂度是O(N2),我们还有没有更好的解法呢?

我们引出了双指针的思想来解决这道题。

使用双指针我们首先要确定双指针,这两个指针的作用分别是什么?

快指针 fastPoint :是我们用来确定新数组的元素值,即不等于目标元素的数组元素。

慢指针 slowPoint :是我们用来确定新数组的下标位置。

确定了双指针的作用,我们就将快指针指向的元素加入到慢指针指向的元素下标中即可。

代码如下(双指针):

    public int removeElement(int[] arr, int val) {
        //定义快慢指针
        //我们要明确快慢指针的含义
        //快指针:用于获取我们新数组中的元素,即在arr中不等于val的数组元素
        int fastPoint = 0;
        //慢指针:用于确定新数组的下标值,即在fastPoint获取到元素后应放在新数组的哪个下标下
        int slowPoint = 0;

        for (; fastPoint < arr.length; fastPoint++) {

            if (arr[fastPoint] != val) {
                arr[slowPoint] = arr[fastPoint];
                slowPoint++;
               //这一步可以简化成
               //arr[slowPoint++] = arr[fastPoint];
            }
        }

        return slowPoint;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值