代码随想录算法训练营第一天| LeetCode704. 二分查找、LeetCode27. 移除元素

二分查找

704.二分查找

题目描述: 704.二分查找.

解法

左闭右闭的二分查找
class Solution(object):
    def search(self, nums, target):
        l, r = 0, len(nums)-1
        while l <= r:	#注意
            m = l + (r-l) // 2
            if nums[m] == target:
                return m
            if nums[m] < target:
                l = m + 1
            else:
                r = m - 1	#注意
        return -1
左闭右开的二分查找
class Solution(object):
    def search(self, nums, target):
        l, r = 0, len(nums)
        while l < r:	#注意
            m = l + (r-l)//2
            if nums[m] == target:
                return m
            elif nums[m] < target:
                l = m + 1
            else:
                r = m	#注意
        return -1

思路

二分查找的方法相对来说比较简单,但是要注意的是查找的区间是左闭右闭还是左闭右开
如果是左闭右闭的区间,那么这个区间的左右两个端点都可以取到,因此left一定小于等于right,在更新端点值时,由于可以取到右端点,所以right应当等于mid-1(因为mid是已经被排除掉的点,所以right不应再取这个点)。
如果是左闭右开的区间,那么就是右端点无法被取到,因此left一定小于right,在更新端点值时,因为mid是被排除掉的值,那么 right应当等于mid(同理mid是被排除掉的点,所以right可以直接等于mid)。

二分查找的相关题目

35.搜索插入位置

题目描述: 35.搜索插入位置.

解法

左闭右闭的二分查找
class Solution(object):
    def searchInsert(self, nums, target):
        l, r = 0, len(nums)-1
        while l <= r:
            m = l + (r-l)//2
            if nums[m] == target:
                return m
            elif nums[m] < target:
                l = m + 1
            else:
                r = m - 1
        return l # r + 1

如果没有找到这个元素的位置,需要将其插入到列表,最后一次循环就一定是left等于right,如果此时mid小于targettarget插入的位置就是mid+1的位置,left此后要**+1right不变,如果此时mid对应的值大于target**,target插入的位置就应该是当前mid位置,right此后要**-1**,所以最终的输出应当是left或者是right+1

左闭右开的二分查找
class Solution(object):
    def searchInsert(self, nums, target):
        l, r = 0, len(nums)
        while l < r:
            m = l + (r-l)//2
            if nums[m] == target:
                return m
            elif nums[m] < target:
                l = m + 1
            else:
                r = m
        return l # r

没有找到这个元素的最后一次循环时,right一定比left1,因此此时的mid指向的是left。如果mid小于targettarget插入的位置就是mid+1,接下来left+1right不变。如果mid大于targettarget插入的位置就是mid所在的位置,此后left不变,right-1。最终的输出就应该是left或者是right

34.在排序数组中查找元素的第一个和最后一个位置

题目描述: 34.在排序数组中查找元素的第一个和最后一个位置.

解法

class Solution(object):
    def searchRange(self, nums, target):
        def findRightBoard(nums,target):	# 寻找右边界
            rightboard = -2
            left, right = 0, len(nums)-1
            while left <= right:
                mid = left + (right-left) // 2
                if nums[mid] <= target:
                    left = mid + 1
                    rightboard = left
                else:
                    right = mid - 1
            return rightboard

        def findLeftBoard(nums, target):	# 寻找左边界
            leftboard = -2
            left,right = 0, len(nums) - 1
            while left <= right:
                mid = left + (right - left) //2
                if nums[mid] >= target:
                    right = mid - 1
                    leftboard = right
                else:
                    left = mid + 1
            return leftboard

        leftboard = findLeftBoard(nums,target)
        rightboard = findRightBoard(nums,target)
        if leftboard == -2 or rightboard == -2:	# 如果没有左右边界,意味着在数字在数组的左或者右侧
            return [-1,-1]
        if rightboard - leftboard > 1:	# 找到边界且中间有内容
            return [leftboard + 1, rightboard - 1]
        return [-1,-1]	# 有边界但是中间没内容

这道题稍微有点难度,还没有考虑只用一个二分法的方法。首先一定要找到边界,左边界是最后一个小于target的数字位置,右边界是第一个大于target的数字位置,如果没有左边界就意味着所有数字都大于target(此时有右边界),如果没有右边界则意味着所有数字都小于target(此时有左边界)
因此可以用两个二分查找分别查找左右边界,如果既有左边界又有右边界,那么就要看这两个边界之间是否有内容了,有内容则意味着target在其中,没有内容的话就要输出[-1,-1]。

69.x的平方根

题目描述: 69.x的平方根.

解法

class Solution(object):
    def mySqrt(self, x):
        if x == 1:
            return 1
        left, right = 0,x//2
        res = 0
        while left <= right:
            mid = left + (right - left)//2
            if mid ** 2 <= x:
                res = mid
                left = mid + 1
            else:
                right = mid - 1
        return res

比较简单,没啥可说的……

367.有效的完全平方数

题目描述: 367.有效的完全平方数.

解法

class Solution(object):
    def isPerfectSquare(self, num):
        if num == 1:
            return True
        left,right = 0, num//2
        while left <= right:
            mid = left + (right - left) // 2
            if mid ** 2 == num:
                return True
            elif mid ** 2 <num:
                left = mid + 1
            else:
                right = mid - 1
        return False

时间上有点慢,不晓得为什么

双指针

27.移除元素

题目描述: 27.移除元素.

解法

在这里插入代码片
class Solution(object):
    def removeElement(self, nums, val):
        slow=0
        for fast in range(len(nums)):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
        return slow

思路

简单的快慢指针,快的指针便利整个数组,通过条件筛选处数值赋给慢指针,慢指针如果内容了就需要向下走一个,那么慢指针的index就是更新后的数组长度。

双指针的相关题目

26.删除有序数组中的重复项

题目描述: 26.删除有序数组中的重复项.

解法

class Solution(object):
    def removeDuplicates(self, nums):
        left = 0
        for right in range(len(nums)):
            if nums[left] != nums[right]:
                left += 1
                nums[left] = nums[right]
        return left + 1

没什么难度,但是要看左指针如何移动,什么时候移动

283.移动零

题目描述: 283.移动零.

解法

class Solution(object):
    def moveZeroes(self, nums):
        left = 0
        for right in range(len(nums)):
            if nums[right] != 0:
                tmp = nums[right]
                nums[right] = nums[left]
                nums[left] = tmp
                left += 1

注意一下要交换位置就好。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值