代码随想录算法-day1

  • LeetCode 704.二分查找
  • LeetCode 27.移除元素

前言

打卡代码随想录算法训练营第49期第一天,希望自己能继续坚持!同时,因为是第一次系统地写代码复现(刷题)的博文,经验不足,文章的结构和内容肯定有所欠缺,后续要逐步优化完善。


LeetCode 704. 二分查找

题目链接
文章讲解
视频讲解

704-1 原始想法

我的初步理解是,二分查找实现的关键在于双下标法,通过不断缩小两下标所夹的区间实现对数组的高效搜索。

704-2 随想录提醒

要注意使用的前提:有序无重复元素的数组
注意区分两种区间设置方法,分别是“左闭右闭”“左闭右开”(与“左开右闭”与“左闭右开”同理,但业界使用较少,“左开右开”很容易出现死循环的问题,要加入额外的判断,不推荐)
由于有两种不同的区间设置,二分查找中有两大坑要注意甄别,关键是区间的开闭设置:

  1. while循环条件的设置,即left和right跳出循环的处理
  2. 更新区间边界是围绕middle的和target的比较结果展开的,要厘清区间更新后是取middle±1还是middle本身

704-3 最终题解

“左闭右闭”实现

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left, right = 0, len(nums)-1
        while (left <= right):
            middle = (left+right)//2 # 这里不用纠结middle是向下还是向上取整,因为middle只代表着区间搜索的方向,不用绝对的精细
            if nums[middle] < target:
                left = middle + 1
            elif nums[middle] > target:
                right = middle - 1
            else: return middle
        return -1

“左闭右开”实现,主要区别就是初始的right取值和right更新的处理

class Solution(object):
    def search(self, nums, target):
        """
        :type nums: List[int]
        :type target: int
        :rtype: int
        """
        left, right = 0, len(nums)
        while (left < right):
            middle = (left+right)//2 # 注意看,这里与“左闭右闭”是一致的,因为middle的取值不起决定作用,只代表区间收缩的方向
            if nums[middle] < target:
                left = middle + 1
            elif nums[middle] > target:
                right = middle
            else: return middle
        return -1

704-4 Debug过程

在代码实现的过程中有一些错误,记录如下:

	 if nums[middle] < target:
	      left = middle + 1
	 elif nums[middle] > target:
	      right = middle - 1
	 else: return middle

以上面中“左闭右闭”为例,最初错误地将elif写为if,导致第一个if独立出来,后面的if和else自成一对,导致满足了第一个if必定会执行else中的return造成错误,与算法中的三种情形无法对应。

	 if nums[middle] < target:
	      left = middle + 1
	 if nums[middle] > target:
	      right = middle - 1
	 else: return middle

LeetCode 27. 移除元素

题目链接
文章讲解
视频讲解

27-1 原始想法

没有想过用暴力方法求解,因为看到了训练营题目讲解中给出的**“双指针法”,自然而然地联想到“二分查找”里采用的首尾指针法**。后来发现,采用随想录里设计的快慢指针法可以在不改变原有数组元素顺序的条件下实现移除,应用场景更广。

27-2 随想录提醒

同上,快慢指针法可以保证不改变数组顺序,且复杂度仅为O(n)

27-3 最终题解

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        fast, slow = 0, 0
        while fast <= len(nums)-1:
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1 
            fast += 1
        return slow
                

27-4 Debug过程

一开始没有真正理解快慢指针的含义,要特别注意,快指针适用于探索数据(遍历数组中的元素),慢指针用于指示符合要求的元素的数量。
由于混淆了快慢指针各自的作用,最初的代码如下:

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        fast, slow = 1, 0
        while fast <= len(nums)-1:
            if nums[slow] == val:
                nums[slow] = nums[fast]
            elif nums[slow] != val:
                slow += 1 
            fast += 1
        return slow

和最终题解的代码对比可以发现,不同的地方有两处,一是fast的初始取值,二是判断条件的对象。尽管while循环条件一致,但正确的方法是对nums[fast]进行判断,而非nums[slow],这表明fast才起到类似于“数据探索”的作用,而slow充其量只发挥索引指示的功能。总的来看,fast是主动的,slow是被动的,要把握好这一态势。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值