5.30 力扣 二分查找 几何题

278. 第一个错误的版本
在这里插入图片描述

# The isBadVersion API is already defined for you.
# @param version, an integer
# @return a bool
# def isBadVersion(version):

class Solution:
    def firstBadVersion(self, n):
        """
        :type n: int
        :rtype: int
        """
        l,r=1,n
        while l<r:
            mid=l+(r-l)//2
            if not isBadVersion(mid):
                l=mid+1
            else:
                r=mid
        return l

34. 在排序数组中查找元素的第一个和最后一个位置
在这里插入图片描述
二分查找的左右边界
左右边界都闭合
二分查找最关键的是如果左右边界取错的情况下容易出现死循环,此时在左右边界都取的情况下避免死循环的处理在于每一次左右边界都要发生改变

def searchleftRange(self,nums: List[int],target: int) ->int:
        lefts,rights = 0,len(nums)-1
        while   lefts <= rights:
    #因为lefts <= rights,所以每次搜索的区间为[lefts,rights]
            mid = (lefts+rights)//2
            if  nums[mid] > target:
                rights = mid-1
    #右侧必须进行回缩,否则在左右区间都取到的情况下可能会发生死循环的现象,
    #比如如果这一句改为了rights = mid,
    #此时如果lefts = 0,rights = 1的情况下mid = (0+1)/2 = 0,
    #如果nums[mid] > target,此时就会无限循环
    #出现lefts = 0,rights = 0的情况时,此时mid = (lefts+rights)/2 = 0,
            elif  nums[mid] < target:
                lefts = mid+1
    #同理左侧也必须进行回缩
            elif  nums[mid] == target:
                rights = mid-1
    #同理相等的时候也必须进行回缩,否则会发生死循环,
    #但此时nums[mid] == target,rights边界向右移动了,
    #所以就会漏掉mid这一区间与target相等的现象
        if  rights+1 < len(nums) and nums[rights+1] == target:
    #跳出循环时单独考虑漏掉的这一种情况
    #因为nums[mid] == target之时,rights = mid-1进行区间放缩,
    #区间内漏掉了相等的数值nums[mid],
    #此时rights = mid-1,mid = rights+1,所以此时返回rights+1
            return  rights+1
        else:
            return  -1

作者:zuo-ni-ai-chi-de-tang-seng-rou
链接:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/solution/li-kou-34ti-xiao-bai-du-neng-kan-dong-de-fang-fa-m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution:
    def searchRange(self, nums: List[int], target: int) -> List[int]:
        if len(nums)==0:
            return [-1,-1]
        left=self.searchleftRange(nums,target)
        right=self.searchrightRange(nums,target)
        return [left,right]
    def searchleftRange(self,nums,target):
        l,r=0,len(nums)-1
        while l<=r:
            mid=l+(r-l)//2
            if nums[mid]<target:
                l=mid+1
            else:
                r=mid-1
        if r+1<len(nums) and nums[r+1]==target:
            return r+1
        else:
            return -1
    def searchrightRange(self,nums,target):
        l,r=0,len(nums)-1
        while l<=r:
            mid=l+(r-l)//2
            if nums[mid]<=target:
                l=mid+1
            else:
                r=mid-1
        if l-1>=0 and nums[l-1]==target:
            return l-1
        else:
            return -1

1266. 访问所有点的最小时间
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    def minTimeToVisitAllPoints(self, points: List[List[int]]) -> int:
        x0,y0=points[0]
        res=0
        for i in range(1,len(points)):
            x1,y1=points[i]
            res+=max(abs(x1-x0),abs(y1-y0))
            x0,y0=x1,y1
        return res

149. 直线上最多的点数
在这里插入图片描述
在这里插入图片描述
我们对所有点遍历,记录包含这个点在内的所有直线中,能组成的点数最多的直线的点数数量,返回这些数量的最大值
我们对一个点遍历的时候,再遍历所有点
维护两个变量
一个来记录和这个点相同的点(重复点)
一个来记录非重复点和这个点组成的各个直线以及它们拥有的点数
即使用哈希表,键为dx/dy,值是这个直线拥有的点数。这里使用 Counter 直接统计各个直线拥有的点数。
返回最多拥有点数的直线所拥有的点数与重复点之和。

from collections import Counter
from decimal import Decimal
class Solution:
    def maxPoints(self, points: List[List[int]]) -> int:
        #Decimal:增加浮点数的境地
        def K(i,j):
            return float('Inf') if i[1] - j[1] == 0 else Decimal(i[0] - j[0]) / Decimal(i[1] - j[1]) 

        if len(points) <= 2:
            return len(points)
        
        maxans = 0
        for i in points:
            # 相同点的个数
            same = sum(1 for j in points if j == i)
            hashmap = Counter([K(i,j) for j in points if j != i])
            tempmax = hashmap.most_common(1)[0][1] if hashmap else 0
            maxans = max(same + tempmax, maxans)
        
        return maxans

593. 有效的正方形
在这里插入图片描述
边长相等,对角线长度相等

class Solution:
    def validSquare(self, p1: List[int], p2: List[int], p3: List[int], p4: List[int]) -> bool:
        def distance(x,y):
            return (y[1]-x[1])**2+(y[0]-x[0])**2
        arr=[p1,p2,p3,p4]
        arr=sorted(arr,key=lambda x:(x[0],x[1]))
        if distance(arr[0],arr[1])!=0 and distance(arr[0],arr[1])==distance(arr[3],arr[1]) and distance(arr[0],arr[3])==distance(arr[2],arr[1]) and  distance(arr[1],arr[3])==distance(arr[2],arr[3]):
            return True
        return False

65. 有效数字
在这里插入图片描述
首先是符号位,表示这个数是正数还是负数。题目当中没有明说,但是我们可以猜测出来,正数用正号表示也是合法的。第二个部分是科学记数法的前半部分,它可以是一个小数。第三个部分是e,即科学记数法当中的e。最后一个部分是整数部分,表示e的指数
在这里插入图片描述

class Solution:
    def isNumber(self, s: str) -> bool:
        s=s.strip()
        number=[str(i) for i in range(10)]
        num_up,num_after,e_up,dot_up=False,False,False,False
        for i in range(len(s)):
            c=s[i]
            if c in number:
                num_up=True
                num_after=True
            elif c in ('+','-'):
                if i>0 and s[i-1]!='e':
                    return False
            elif c=='.':
                if e_up or dot_up:
                    return False
                dot_up=True
            elif c=='e':
                if e_up or not num_up:
                    return False
                e_up=True
                num_up=False
            else:
                return False
        return num_up and num_after

正则表达式匹配:
在这里插入图片描述

import re
class Solution:
    def isNumber(self, s: str) -> bool:
        pat=re.compile(r'^[+-]?(\d+\.\d+|\.\d+|\d+\.|\d+)(e[+-]?\d+)?$')
        #去掉首尾空格
        if len(re.findall(pat,s.strip())):
            return True
        else:
            return False

836. 矩形重叠
在这里插入图片描述
没有重叠的情况:
矩形 rec1 在矩形 rec2 的左侧; rec1[2] <= rec2[0]
矩形 rec1 在矩形 rec2 的右侧;rec1[0] >= rec2[2]
矩形 rec1 在矩形 rec2 的上方;rec1[1] >= rec2[3]
矩形 rec1 在矩形 rec2 的下方; rec1[3] <= rec2[1]

class Solution(object):
    def isRectangleOverlap(self, rec1, rec2):
        return not (rec1[2] <= rec2[0] or  # left
                    rec1[3] <= rec2[1] or  # bottom
                    rec1[0] >= rec2[2] or  # right
                    rec1[1] >= rec2[3])    # top

法二:检查区域
矩形重叠说明 投影到x,y轴上的线段有重叠,说明 min(rec2[2],rec1[2])>max(rec2[0],rec1[0])
min(rec2[3],rec1[3])>max(rec2[1],rec1[1])
在这里插入图片描述

class Solution:
    def isRectangleOverlap(self, rec1: List[int], rec2: List[int]) -> bool:
        return  min(rec2[2],rec1[2])>max(rec2[0],rec1[0]) and  min(rec2[3],rec1[3])>max(rec2[1],rec1[1]) 

在这里插入图片描述
223. 矩形面积
在这里插入图片描述
没有重叠的情况:
在这里插入图片描述
重叠区域:
上边界,取两个矩形的上边界的最小值
下边界,取两个矩形的下边界的最大值
左边界,取两个矩形的左边界的最大值
右边界,取两个矩形的右边界的最小值

class Solution:
    def computeArea(self, A: int, B: int, C: int, D: int, E: int, F: int, G: int, H: int) -> int:
        #将靠左的挪到前面
        if A>E:
            return self.computeArea(E,F,G,H,A,B,C,D)
        #如果没有重叠
        if B>=H or D<=F or E>=C:
            return  abs(C-A)*abs(D-B)+abs(G-E)*abs(H-F)
        up=min(D,H)
        down=max(B,F)
        left=max(A,E)
        right=min(C,G)
        return  abs(C-A)*abs(D-B)+abs(G-E)*abs(H-F)-abs(up-down)*abs(right-left)

883. 三维形体投影面积
在这里插入图片描述
在这里插入图片描述
从顶部看是 网格中非零值的数目
从侧面看,由该形状生成的阴影将是网格中每一行的最大值。
从前面看,由该形状生成的阴影将是网格中每一列的最大值。

class Solution:
    def projectionArea(self, grid: List[List[int]]) -> int: 
        res=0
        for i in range(len(grid)):
            max_h=0
            max_l=0
            for j in range(len(grid)):
                if grid[i][j]!=0:
                    res+=1
                #从侧面看,i不变时的最大值
                max_l=max(max_l,grid[i][j])
                #从正面看,j不变时的最大值
                max_h=max(max_h,grid[j][i])
            res+=max_h+max_l
        return res

面试题 16.14. 最佳直线
在这里插入图片描述
用一个字典保存已找到的所有直线的出现次数,和其穿过的下标最小的两个点的下标
遍历所有点对,更新字典及最优解

class Solution:
    def bestLine(self, points: List[List[int]]) -> List[int]:
        d = {}
        x = y = 0
        maxCount = 0
        for i in range(len(points)):
            for j in range(i+1, len(points)):
                k, b = self.f([points[i], points[j]])
                if (k, b) in d.keys():
                    d[(k, b)][0] += 1
                else:
                    d[(k, b)] = [1, (i, j)]
                if d[(k, b)][0] > maxCount or (d[(k, b)][0] == maxCount and d[(k, b)][1][0] < x) or (d[(k, b)][0] == maxCount and d[(k, b)][1][1] < y):
                    maxCount = d[(k, b)][0]
                    x, y = d[(k, b)][1]
                print(x, y)
        return [x, y]

    # 求两点之间连线的k和b
    def f(self, points: List[List[int]]) -> List[int]:
        if points[0][0] == points[1][0]:
            return [float('inf'), points[0][0]]
        else:
            return [(points[1][1]-points[0][1]) / (points[1][0]-points[0][0]),
            (points[0][1]*points[1][0]-points[1][1]*points[0][0]) / (points[1][0]-points[0][0])]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值