小白刷代码随想录day1 --704二分查找,27数组移除元素

秋招没有收到满意的offer, 总结了以下可能是自己的硬实力还不够导致自己没有十足的自信。从现在开始刷代码随想录提升自己的代码能力,也开始锻炼着写写博客总结思路。虽然还是很小白的选手,但是还是希望自己能够坚持下来有所收获。不说了,上题!

704. 二分查找

题目

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

来源:力扣(LeetCode)https://leetcode.cn/problems/binary-search

初始思路

最开始没有考虑到去优化时间复杂度,直接采用暴力解法遍历一整个数组。虽然自己解出来了,但是时间复杂度为O(n), 后面看到二分法后知道了这并不是最优。

初始解法 be like:

class Solution {
    public int search(int[] nums, int target) {
        int result = -1; //初始化返回结果为-1
        for(int i =0; i < nums.length; i++){
            if (nums[i] == target){
                result = i; //当目标值存在,返回结果赋值为目标值下标
            }
        }
        return result;
    }
}

优化解法--二分法

 由于初始思路太过没有学问(不是),在看到推荐解法二分法之后知道了为什么要用二分法。题目中存在着一个可以使用二分法最大的前提条件,那就是“有序(升序)”数组。对于一个有序数组,数组中的元素要么由小到大,要么由大到小。因此我们可以选取他们的中点mid作为与寻找目标target的比较对象,若相等则返回mid,若不相等则查找范围可以缩小一半。我们以本题所指的升序数组为例:

已知升序数组nums和寻找目标target。数组nums的初始查找范围为整个数组,定义为[left, right]。取nums的中点mid:

  • 如果 nums[mid] = target, 则target在下标mid的元素上;

  • 如果 nums[mid] > target, 则target在下标mid元素的左侧;(因为升序,所以mid右侧的元素的值肯定比mid还要大,就不用比较了)

  • 如果 nums[mid] < target, 则target在下标mid元素的右侧;(同上)

这样,每次都取中点mid与target进行比较,查找范围由原来的整个数组变为1/2个数组再变为1/4个数组......直至查找结束。由于每次查找范围都缩小了一半,因此二分法查找的时间复杂度为O(log n)。

这里有朋友可能要问查找结束的条件是什么。没错,当时我也是这么问的。由于二分法查找的条件为:查找范围不为空,即left<=right。因此,如果target不在数组中,当left > right的时候查找结束,返回-1。

具体代码如下:

class Solution {
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = (right - left) / 2 + left;
            int num = nums[mid];
            if (num == target) {
                return mid;
            } else if (num > target) {
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }
        return -1;
    }
}

作者:LeetCode-Solution

27. 数组移除元素

如果说上一个题我还能用一些暴力解法硬给做出来,那这个题就是真正弥补了我知识上的欠缺。(我是小白,大佬别理我)

题目

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

来源:力扣(LeetCode)https://leetcode.cn/problems/remove-element

初始思路

想要用remove() 或者del() 方法直接删除数组中的元素。

然后很明显的,做不出来。

理论欠缺

这里我想要直接删除数组元素其实是一个没有理解数组定义而犯下的非常明显的错误。这里建议直接去看卡哥的视频讲解https://www.bilibili.com/video/BV12A4y1Z7LP/?vd_source=2b661ed7e8639bf2834608f46f8c8d5f。根据数组的定义,数组是连续的。因此不能直接删除,只能“覆盖”。换句话来说,在数组中,删除即覆盖

在卡哥的视频中也讲到,可以通过两个for循环暴力删除,但这样显而易见不是最优。因此这里我又学到了一个非常好的方法,即双指针法。

双指针法

双指针法在卡哥的视频中讲的也很清楚。这里如果有时间的化我再详细补充图文。简单说双指针法包含两个指针,一个fast指针,一个slow指针。

fast指针:用于定位需要保留的元素。

slow指针:用于定位保留的元素所覆盖的位置。

这样,fast指针定位到的可以保留的元素就覆盖到slow指针所在的位置。而需要删除的元素就不会被fast指针定位到,因此也不会赋值给slow指针所在的位置,从而做到了被其他可以保留的元素覆盖。

具体代码如下:

class Solution {
    public int removeElement(int[] nums, int val) {
        int n = nums.length;
        int left = 0;
        for (int right = 0; right < n; right++) {
            if (nums[right] != val) {
                nums[left] = nums[right];
                left++;
            }
        }
        return left;
    }
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/remove-element/solution/yi-chu-yuan-su-by-leetcode-solution-svxi/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值