You are given two positive integers xCorner and yCorner, and a 2D array circles, where circles[i] = [xᵢ, yᵢ, rᵢ] denotes a circle with center at (xᵢ, yᵢ) and radius rᵢ.
There is a rectangle in the coordinate plane with its bottom left corner at the origin and top right corner at the coordinate (xCorner, yCorner). You need to check whether there is a path from the bottom left corner to the top right corner such that the entire path lies inside the rectangle, does not touch or lie inside any circle, and touches the rectangle only at the two corners.
Return true if such a path exists, and false otherwise.
importpytestfromsolutionimportSolution@pytest.mark.parametrize('x, y, circles, expected',[(3,4,[[2,1,1]],True),(3,3,[[1,1,2]],False),(3,3,[[2,1,1],[1,2,1]],False),(4,4,[[5,5,1]],True),(3,3,[[1,2,1],[1,4,1],[2,5,1],[4,5,1],[5,4,1],[5,2,1],[4,2,1]],True),(3,3,[[2,10,7],[10,2,7]],True),(3,3,[[2,1000,997],[1000,2,997]],True),(22742157,210809967,[[22741186,210810964,200],[22741869,210809432,165],[22742256,210810275,182],[22742089,210809693,129],[22741912,210810128,196],[22741658,210809205,144],[22741648,210809094,118],[22741920,210809808,128]],False),(8,8,[[1,4,1],[3,4,1],[5,4,1],[7,4,1]],False),])deftest_can_reach_corner(x,y,circles,expected):sol=Solution()assertsol.canReachCorner(x,y,circles)==expected
fromtypingimportListR=1L=R<<1B=L<<1T=B<<1TB=T|BLR=L|RLB=L|BRT=R|TclassCluster:def__init__(self,circle:List[int],edges:int):self.circles=[circle]self.edges=edges# cross edges bit map 0bTBLRx,y,r=circleself.top=y+rself.bottom=y-rself.left=x-rself.right=x+rdefmerge(self,other:'Cluster'):self.circles.extend(other.circles)self.edges|=other.edgesself.top=max(self.top,other.top)self.bottom=min(self.bottom,other.bottom)self.left=min(self.left,other.left)self.right=max(self.right,other.right)defis_out_of_bound(self,circle:List[int]):x,y,r=circlereturnx+r<self.leftorx-r>self.rightory+r<self.bottomory-r>self.topclassSolution:defcanReachCorner(self,xCorner:int,yCorner:int,circles:List[List[int]])->bool:clusters=[]forcircleincircles:edges,out_of_rect=self._calc_crossed_edges(xCorner,yCorner,circle)ifself._is_unreachable(edges):returnFalseifout_of_rect:continuenew_clusters=[]this_cluster=Cluster(circle,edges)forclusterinclusters:# A quick prune.ifcluster.is_out_of_bound(circle):new_clusters.append(cluster)continueforcircle2incluster.circles:ifself._are_circles_connected_inside_rect(circle,circle2,xCorner,yCorner):this_cluster.merge(cluster)ifself._is_unreachable(this_cluster.edges):returnFalsebreakelse:new_clusters.append(cluster)new_clusters.append(this_cluster)clusters=new_clustersreturnTruedef_are_circles_connected(self,circle1:List[int],circle2:List[int])->bool:x1,y1,r1=circle1x2,y2,r2=circle2# Prune by bound box.ifx2+r2<x1-r1orx2-r2>x1+r1ory2+r2<y1-r1ory2-r2>y1+r1:returnFalsedistance_square=(x1-x2)**2+(y1-y2)**2radius_sum_square=(r1+r2)**2returndistance_square<=radius_sum_squaredef_are_circles_connected_inside_rect(self,circle1,circle2,xCorner,yCorner)->bool:ifnotself._are_circles_connected(circle1,circle2):returnFalsex1,y1,r1=circle1x2,y2,r2=circle2# (x1, y1)--(x, y) : (x, y)--(x2, y2) = r1 : r2# Check if (x, y) inside rect.if(-x1*(r1+r2)<=(x2-x1)*r1<=(xCorner-x1)*(r1+r2)and-y1*(r1+r2)<=(y2-y1)*r1<=(yCorner-y1)*(r1+r2)):returnTruereturnFalsedef_is_h_line_cross_circle(self,left:int,right:int,y:int,circle:List[int])->bool:cx,cy,r=circle# Check if line is far away from circle.ifabs(y-cy)>r:returnFalse# Check if left endpoint inside circle.r_square=r**2if(left-cx)**2+(y-cy)**2<=r_square:returnTrue# Check if right endpoint inside circle.if(right-cx)**2+(y-cy)**2<=r_square:returnTrue# Check if the two endpoints apart from the perpendicular line.ifleft<cx<right:returnTruereturnFalsedef_is_v_line_cross_circle(self,bottom:int,top:int,x:int,circle:List[int])->bool:cx,cy,r=circle# Check if line is far away from circle.r_square=r**2ifabs(x-cx)>r:returnFalse# Check if bottom endpoint inside circle.if(x-cx)**2+(bottom-cy)**2<=r_square:returnTrue# Check if top endpoint inside circle.if(x-cx)**2+(top-cy)**2<=r_square:returnTrue# Check if the two endpoints apart from the perpendicular line.ifbottom<cy<top:returnTruereturnFalsedef_calc_crossed_edges(self,xCorner,yCorner,circle)->tuple[int,bool]:edges=0ifself._is_h_line_cross_circle(0,xCorner,yCorner,circle):edges|=Tifself._is_h_line_cross_circle(0,xCorner,0,circle):edges|=Bifself._is_v_line_cross_circle(0,yCorner,xCorner,circle):edges|=Rifself._is_v_line_cross_circle(0,yCorner,0,circle):edges|=Lcx,cy,_=circleout_of_rect=edges==0andnot(0<cx<xCornerand0<cy<yCorner)returnedges,out_of_rectdef_is_unreachable(self,edges:int)->bool:returnedges&TB==TBoredges&LR==LRoredges&LB==LBoredges&RT==RT
评论需要 JavaScript。