【代码随想录刷题笔记】704二分查找、27移除元素

704 二分查找

题目链接:
https://leetcode.cn/problems/binary-search/
文章讲解:
https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html
视频讲解:
https://www.bilibili.com/video/BV1fA4y1o715

  • 注意事项
    1,使用二分查找,数组必须是有序的。此题已经排序,否则需要自己进行排序。
    2,题目已经假设,数组中的数都是不重复的,因为如果重复,结果就不唯一了。
    3,对区间的定义不同,有两种写法,一种是左闭右闭,一种是左闭右开(其他两种不太常用,硬写也行,没有必要而已)。个人比较习惯左闭右闭的写法。
    4,区间的定义可以认为是一种模式,一旦选择了某种模式,后面循环条件、变量初始化、变量更新等,就不要违反它。

  • 第一种写法,左闭右闭:

class Solution(object):
    def search(self, nums, target):
        n = len(nums)
        if n == 0:
            return -1

		# 从数组的两端向中间查找
        left = 0
        right = n-1 # 因为右闭,所以right=n-1,如果right=n,就会发生越界的错误

        while(left <= right): 
        # 用<=而不是<的原因是,由于左闭右闭,当left=right的时候,区间仍是有效的
        # 如果使用<号,就会跳过中间那一个数,导致结果不对
            mid = (left + right) // 2
            if (nums[mid] > target):
            	# mid已经不是要找的数,所以right要更新为mid的前一个数,由于右闭,取mid-1
                right = mid - 1 
            elif (nums[mid] < target):
            	# 同理,mid已经不是要找的数,所以left要更新为mid的下一个数,由于左闭,取mid+1
                left = mid + 1
            else:
                return mid
        return -1
  • 第二种写法,左闭右开:
class Solution(object):
    def search(self, nums, target):
        n = len(nums)
        if n == 0:
            return -1

		# 从数组的两端向中间查找
        left = 0
        right = n # 因为右开,所以right=n,实际上right取不到n,所以不会有越界错误

        while(left < right): 
        # 用<的原因是,由于左闭右开,当left=right的时候,区间已经无效了,说明此时循环应该结束
            mid = (left + right) // 2
            if (nums[mid] > target):
            	# mid已经不是要找的数,所以right要更新为mid的前一个数,由于右开,取right=mid
                right = mid
            elif (nums[mid] < target):
            	# 同理,mid已经不是要找的数,所以left要更新为mid的下一个数,由于左闭,取mid+1
                left = mid + 1
            else:
                return mid
        return -1
  • 总结:
    对区间的定义不同,影响的有三个地方:(1)指针的初始化;(2)循环结束的条件;(3)指针的更新方式。

27 移除元素

题目链接:
https://leetcode.cn/problems/remove-element/
文章讲解:
https://programmercarl.com/0027.%E7%A7%BB%E9%99%A4%E5%85%83%E7%B4%A0.html
视频讲解:
https://www.bilibili.com/video/BV12A4y1Z7LP

  • 注意事项
    1,数组在内存空间的地址是连续的,删除其实等于覆盖。
    2,如果每次找到一个元素,都把后面所有元素整体移动一轮,那么时间复杂度是O(n*n)
    3,如果使用快慢指针,只需要遍历一次,就可以把所需要的数字都写到对应的位置,最终返回新数组的长度即可。
class Solution(object):
    def removeElement(self, nums, val):
        n = len(nums)
        slow = 0 # 快慢指针都指向第一个元素,这样就不用额外处理第一个元素是否为val的情况
        fast = 0

        while(fast < n):# 当快指针遍历到数组的末尾,循环结束
            if nums[fast] != val: # 注意这里是移除元素,所以不等于val的才是我们要找的值
                nums[slow] = nums[fast] # 找到有效的数字,就进行赋值,然后快慢指针都移动
                slow += 1
                fast += 1
            else:
                fast += 1 # 否则快指针继续向后寻找
        
        return slow # 最后一次赋值后,slow指针有+1,因此此时slow的数值就是数组的长度
  • 总结:
    最开始想到的方法是使用left和right指针,初始化在数组的两头,同时向中间收缩,right遇到有效数字,就赋值给left,但是写了一下发现,要处理的边界问题会很多。同向遍历,是最简单和清晰的写法,我劝大家不要为难自己…
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值