代码随想录day01| 704. 二分查找、27. 移除元素

目录

704 二分查找

27 移除元素


704 二分查找

题目链接

代码随想录题解

看到题目的第一想法:这道题之前刷过,采用二分法来获取有序数组某个元素的位置,但是边界的处理上感觉自己处理的很不规范,而自己也没有好的解决方法。

看完代码随想录之后的想法:卡哥的循环不变量有效解决了边界处理上模棱两可的问题,在做二分查找时,可以明确的规定左闭右闭或者左闭右开的边界处理规则,这对算法的初学者很友好。

  •  此处的循环不变量即区间的左右边界是明确的,是已经想清楚的。

 代码实现:

区间为左闭右闭时:

class Solution {
    public int search(int[] nums, int target) {
        //二分查找,左闭右闭
        int length = nums.length;
        int left = 0, right = length - 1, mid;
        while (left <= right) {
            //防止越界,为什么这样可以防止越界?
            mid = left + (right - left) / 2;
            if (target == nums[mid]) {
                return mid;
            } else if (target > nums[mid]) {
                left = mid + 1;
            }else {
                right = mid - 1;
            }
        }
        return -1;
    }
}

区间为左闭右开时:

class Solution {
    public int search(int[] nums, int target) {
        //二分查找,左闭右开
        int length = nums.length;
        int left = 0, right = length, mid;
        while (left < right) {
            //防止越界,为什么这样可以防止越界?
            mid = left + (right - left) / 2;
            if (target == nums[mid]) {
                return mid;
            } else if (target > nums[mid]) {
                left = mid + 1;
            }else {
                right = mid;
            }
        }
        return -1;
    }
}

实现过程中遇到哪些困难:

  • while循环的终止条件:left <= right or left < right ?
    • 对于左闭右闭区间,left == right 即指向同一个元素时,是需要进入while循环处理具体逻辑的,可以拿长度为1的数组模拟一下。
    • 对于左闭右开区间,同样拿长度为1的数组模拟一下,若left == right,则唯一的元素始终无法进入while循环,这显然是有问题的,故使用left < right。
  • mid的取值:为什么使用mid = left + (right - left) / 2 就能防止溢出,而mid = (left + right) / 2就可能会导致溢出
    • 此处的越界应该是相对于int的取值范围而言,(left + right)可能超过int的取值范围,造成溢出,影响计算的准确性;而mid = left + (right - left) / 2的写法显然没有溢出问题。

27 移除元素

题目链接

代码随想录题解

看到题目的第一想法:这道题(原地的移除元素)之前也刷过,看到题后没想到用双指针法,并且暴力解法也没有思路。

看完代码随想录之后的想法:

  • 双指针法:fast指针一直往右走,若遇到指针指向的值与val不相等时,则将此处的值覆盖slow所指向位置的值,最终数组中所有元素的值都不等于val,且slow此时的值即为新数组的长度。
  • 暴力解法:需要两层循环,第一层循环先寻找与val相等的元素值,找到后,采用第二层循环将此元素值后方的值整体向前移动一位,并且第一层循环的轮次要-1,因为之前已经自增1,-1是为了让 i 再次回到之前值,并且数组size-1。

代码实现:

双指针法

class Solution {
    public int removeElement(int[] nums, int val) {
        //暴力解法暂时没想到,后参照代码随想录里的暴力解法
        //快慢指针法
        int fast= 0, slow = 0;
        int length = nums.length;
        while (fast < length) {
            if (val != nums[fast]) {
                if (fast != slow) {
                    nums[slow] = nums[fast];
                }           
                slow++;
            }
            fast++;
        }
        //为什么不是slow-1,以3 2 2 3 val=3为例,slow从0开始,slow=2时结束循环,此时长度刚好为2,而非2-1
        return slow;
    }
}

暴力解法

class Solution {
    public int removeElement(int[] nums, int val) {
        //暴力解法暂时没想到,后参照代码随想录里的暴力解法
        //暴力法:遍历数组,遇到与val相等的元素值时,整体左移一位,遍历轮次值-1,size-1
        //使用双层for循环
        int size = nums.length;
        for (int i = 0; i < size; i++) {
            //第一层循环查看是否有要移除的元素,若有,才进入第二层循环,否则没有必要
            if (nums[i] == val) {
                for (int j = i + 1; j < size; j++) {
                    nums[j - 1] = nums[j];
                }
                //循环位置需还原,即左移一次
                i--;
                //数组长度-1
                size--;
            }
            
        }
        return size;
    }
}

实现过程中遇到哪些困难:

  • 双指针法何时移动slow指针?
    • 当val != nums[fast]时,需要首先①将fast指针的值覆盖slow指针指向的值,②而后slow++,如果顺序为②①,则会导致有些等于val的元素未能被移除
  • 暴力解法:为什么要先判断val == nums[i],而后进入第二层循环,而不知进入第二层循环后再判断val == nums[i] ?
    • 一层循环后直接判断val与nums[i]是否相等,可以减少后面循环的次数,一定程度上降低了时间复杂度。

今日收获,记录一下自己的学习时长

  • 算法处理约2h,博客编写约1.5h
  • 熟悉了二分查找与双指针法,编写博客也是对自己思路的梳理~
  • 贵在坚持,加油!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值