arrays - Python代码查找其总和与特定值匹配的最小行数
问题描述
我正在参加一个代码挑战测试,该测试需要编写一个函数,该函数返回用于照亮多条街道的最少交通信号灯数量。
街道编号表示为一条直线,范围为 0:n,其中可以在 n 的任何位置添加灯光,以及一个称为灯光的二维数组,表示灯光的位置及其强度,强度定义范围光(将是左右)[位置+强度,位置-强度],例如。[3,5] 灯位于位置 3,可点亮范围为 (-2 : 8 )。我们需要检查照亮整个街道所需的最小灯并将其返回,如果不可能,则返回 -1
例子
n=10 , lights= [[0,5],[1,3],[5,4],[8,3]]
result=2 因为 [0,5] & [8,3] 可以匹配条件。
我的问题
现在我需要帮助如何在数组上循环并找到它们的联合达到特定条件的最小行数[范围(0,n + 1),我需要一个循环来尝试单行然后如果条件不是匹配然后尝试每 2 行的并集,如果不匹配则尝试每三行的并集,直到最大限制为 no。数组中的行数,如果条件匹配则返回匹配条件所需的最小行数,如果条件不满足则返回 -1 注意:我需要知道如何执行循环,我可以编写代码但是我并没有想到通用方程的想法
详细示例
Array =[[0,4],[0,5],[5,10],[1,9]] n=10
那么范围将是 (0:11) 将是 [0:10]
- 检查行 (0,1,2,3) 如果它们中的任何一个可以覆盖整个范围,则返回 1
- 如果上面不匹配,检查行 [[0,1],[0,2],[0,3],[1,2],[1,3],[2,3]] 的并集,如果有的话它们覆盖了整个范围,然后返回 2
- 如果以上不匹配,请检查数组中 3 行 [[0,1,2],[0,1,3],[1,2,3]] 的行的并集
- 如果所有条件都不匹配,则返回 -1
我试图编写一个代码,但我找不到一种方法如何使它简单和递归,我的方法是使用 for 循环进行第一次迭代,然后使用 2 个 for 循环进行迭代 2,然后使用 3 个循环,依此类推,效率不高如果矩阵尺寸很大,则不可能
# check if only 1 light can light up all the streets
for i in range (arr2.shape[0]):
for j in range (arr2.shape[1]-1):
lights_up=[0,0,0,0,0,0,0,0,0,0,0]
for z in range (arr2[i][j], arr2[i][j+1]+1):
print 'z= ',z
lights_up[z]=1
print ("iteration_",i,j,lights_up)
if lights_up==[1,1,1,1,1,1,1,1,1,1,1]:
Min_lights=1
print lights_up # to be hashed
break
if Min_lights != -1:
break
print Min_lights
#check if 2 light can ligh up
解决方案
我的初步做法如下:
注意:我使用 numpy 数组来保存覆盖图,因为它使按 cols 对一组行进行切片更容易。
import numpy as np
def minLights(n: int, l : list) -> int:
# Create a street coverage map for each light
cm = []
for i, v in enumerate(l):
k = [False] * n
k[v[0]] = True
for x in range(-v[1], v[1]+1):
if v[0] + x >= 0 and v[0] + x < n:
k[v[0] + x] = True
cm.append(k)
cm = np.array(cm)
cnt = 0
# Walk coverage map looking for a combination covering all
while cnt < len(l):
for row in range(len(l)):
covered = True
for col in range(n):
# Testing for all False Coverage in Col
if not cm[row:row+cnt+1, col].any():
covered = False
break
if covered:
return cnt +1
cnt += 1
return -1
在对初始方法进行了一些更广泛的测试后,我发现在最佳解决方案涉及非序列灯的情况下,该方法无法确定最佳解决方案。这促使创建了下面的第二种方法,该方法使用优先级队列来保存增量解决方案。优先权重被选择为未覆盖的街道段数 * 使用的灯数。该解决方案如下:
改进的解决方案
import heapq as hq
class Coverage:
def __init__(self, n, rw, lt):
self.n = n
self.map = buildCoverage(self.n, lt)
self.includes = {rw}
self.w = len(self.includes)*self.map.count(False)
def add(self, rw, lt):
if rw not in self.includes:
lmap = buildCoverage(self.n, lt)
self.merge(lmap)
self.includes.add(rw)
self.w = len(self.includes)* self.map.count(False)
return self.weight
return -1
def merge(self, ltmap):
for i in range(len(self.map)):
if ltmap[i] or self.map[i]:
self.map[i] = True
@property
def weight(self):
return self.w
@property
def solution(self):
return len(self.includes)
def __lt__(self, other):
return self.weight < other.weight
def buildCoverage(n, lt):
rslt = [False]*n
rslt[lt[0]] = True
for x in range(-lt[1], lt[1] +1):
if lt[0] + x >= 0 and lt[0] + x < n:
rslt[lt[0] + x ] = True
return rslt
def minLightsq(n: int, l : list) -> int:
q = []
for rw, lt in enumerate(l):
nd = Coverage(n, rw, lt)
#q.append((nd.weight, nd))
hq.heappush(q, nd)
while len(q) > 0:
# q = sorted(q, key= lambda x: x[0], reverse= True)
# nd = q.pop()[1]
nd = hq.heappop(q)
if nd.weight == 0:
return nd.solution
for rw, lt in enumerate(l):
w = nd.add(rw, lt)
if w >= 0:
if w == 0:
return len(nd.includes)
#q.append((w, nd))
hq.heappush(q, nd)
return -1
推荐阅读
- c# - 反序列化泛型类型protobuf c#
- perl - 接受列表并创建对象的 Perl 模块
- mongodb-3.6 - Mongodb 3.6 changestream resumeToken 时间戳
- python - 用该组中的第一个非空值填充组中的所有值
- javascript - 如何修复段落中的文本长度?
- mysql - AVG*COUNT 返回一个浮点值
- r - 根据组内的特定行在 group_by 内进行变异
- java - Spring Boot 拦截器释放静态资源
- angularjs - 在 Ionic Typescript 中实现脚本
- python - 如何矢量化这个 numpy 旋转代码?