长度为t
的数组将所有元素初始化为1。现在我们可以对数组执行两种类型的查询
i
索引处的元素替换为0.此查询由0 index 1
的索引;如果没有这样的索引,则打印-1
。此查询用1 k 现在假设对于长度为t=4
的数组,其开头的所有元素现在都是[1,1,1,1]
,现在查询0 2
数组变为[1,0,1,1]
,查询1 3
输出结果为4
我使用过暴力方法,但如何提高代码效率呢?
n,q=4,2
arr=[1]*4
for i in range(q):
a,b=map(int,input().split())
if a==0:
arr[b-1]=0
else:
flag=True
count=0
target=b
for i,j in enumerate(arr):
if j ==1:
count+=1
if count==target:
print(i+1)
flag=False
break
if flag:
print(-1)
我还尝试先在列表中附加1的所有索引,然后进行二分查找,但弹出0会更改代码失败的索引
def binary_search(low,high,b):
while(low<=high):
mid=((high+low)//2)
#print(mid)
if mid+1==b:
print(stack[mid]+1)
return
elif mid+1>b:
high=mid-1
else:
low=mid+1
n=int(input())
q=int(input())
stack=list(range(n))
for i in range(q):
a,b=map(int,input().split())
if a==0:
stack.pop(b-1)
print(stack)
else:
if len(stack)<b:
print(-1)
continue
else:
low=0
high=len(stack)-1
binary_search(low,high,b)
答案 0 :(得分:3)
您可以构建一个二叉树,其中每个节点都会为您提供位于其下方和左侧的数量。因此,如果 n 为7,那么该树最初看起来像这样(所有的实际列表都显示在它下面):
4
/ \
2 2
/ \ / \
1 1 1 1
----------------
1 1 1 1 1 1 1 -
将索引4(从零开始)的数组元素设置为0,会将该树更改为:
4
/ \
2 1*
/ \ / \
1 1 0* 1
----------------
1 1 1 1 0*1 1 -
因此,设置0表示 O(log(n))时间复杂度。
通过对节点值求和,同时沿着正确的方向向下降树,可以在相同的时间复杂度下计算1的数量。
这是您可以使用的Python代码。它代表list in breadth-first order中的树。我没有竭尽全力进一步优化代码,但它具有上述时间复杂性:
class Ones:
def __init__(self, n): # O(n)
self.lst = [1] * n
self.one_count = n
self.tree = []
self.size = 1 << (n-1).bit_length()
at_left = self.size // 2
width = 1
while width <= at_left:
self.tree.extend([at_left//width] * width)
width *= 2
def clear_index(self, i): # O(logn)
if i >= len(self.lst) or self.lst[i] == 0:
return
self.one_count -= 1
self.lst[i] = 0
# Update tree
j = 0
bit = self.size >> 1
while bit >= 1:
go_right = (i & bit) > 0
if not go_right:
self.tree[j] -= 1
j = j*2 + 1 + go_right
bit >>= 1
def get_index_of_ith_one(self, num_ones): # O(logn)
if num_ones <= 0 or num_ones > self.one_count:
return -1
j = 0
k = 0
bit = self.size >> 1
while bit >= 1:
go_right = num_ones > self.tree[j]
if go_right:
k |= bit
num_ones -= self.tree[j]
j = j*2 + 1 + go_right
bit >>= 1
return k
def is_consistent(self): # Only for debugging
# Check that list can be derived by calling get_index_of_ith_one for all i
lst = [0] * len(self.lst)
for i in range(1, self.one_count+1):
lst[self.get_index_of_ith_one(i)] = 1
return lst == self.lst
# Example use
ones = Ones(12)
print('tree', ones.tree)
ones.clear_index(5)
ones.clear_index(2)
ones.clear_index(1)
ones.clear_index(10)
print('tree', ones.tree)
print('lst', ones.lst)
print('consistent = ', ones.is_consistent())
请注意,这会将索引视为从零开始,而方法get_index_of_ith_one
需要一个至少为1的参数(但它返回一个从零开始的索引)。
应该很容易适应您的需求。
答案 1 :(得分:2)
让我们从一些常规技巧开始:
在迭代之前检查第n个元素是否对于列表来说太大。如果您还保留一个存储零个数的“计数器”,您甚至可以检查nth >= len(the_list) - number_of_zeros
(不确定>=
是否正确,这个示例似乎使用了基于1的索引,所以我可能是一个一个)。这样,只要使用太大的值,就可以节省时间。
使用更高效的功能。
因此,您可以使用input
代替sys.stdin.readline
而不是binary_search
(请注意它将包含尾随换行符)。
而且,即使它在这种情况下可能没有用,内置的bisect
模块也会比你创建的for _ in itertools.repeat(None, q)
函数更好。
您也可以使用for i in range(q)
代替if j
,这样会更快,而且您不需要该索引。
然后,您可以使用一些更专业的事实来改进代码:
您只存储0和1,因此您可以使用if not j
检查1和n
来检查零。这些比手动比较快一点,尤其是当你在循环中这样做时。
每次查找第n个1时,您都可以创建一个包含遇到的O(1)
s +索引的临时字典(或列表)。然后重复使用该dict进行后续查询(dict-lookup和list-random-access为O(n)
,而搜索为for index, item in enumerate(arr):
)。如果您有后续查询而没有中间更改,您甚至可以扩展它。
但是,如果发生更改,您需要丢弃该字典(或列表)或更新它。
一些挑剔:
变量名称不是很具描述性,您可以使用i
代替j
和arr
。
您使用的是列表,因此i
是一个误导性的变量名称。
您有两个enumerate
个变数。
但不要误会我的意思。这是一次非常好的尝试,而且您使用range
代替{{1}}这一事实非常棒,并且表明您已经编写了pythonic代码。
答案 2 :(得分:2)
考虑类似于区间树的东西:
替换和搜索查询都可以在对数时间内完成。
答案 3 :(得分:0)
使用较少的行进行重构,因此在行数方面更有效,但运行时间可能与O(n)相同。
n,q=4,2
arr=[1]*4
for i in range(q):
query, target = map(int,input('query target: ').split())
if query == 0:
arr[target-1] = 0
else:
count=0
items = enumerate(arr, 1)
try:
while count < target:
index, item = next(items)
count += item
except StopIteration as e:
index = -1
print(index)
假设arr
仅包含1和0 - 在将其添加到计数之前,您不必检查项目是否为1,添加零无效。
要检查标记,只需在枚举对象(items
)上继续调用,直到达到目标或arr
结尾。
为了提高运行效率,使用外部库但基本相同的过程(算法):
import numpy as np
for i in range(q):
query, target = map(int,input('query target: ').split())
if query == 0:
arr[target-1] = 0
else:
index = -1
a = np.array(arr).cumsum() == target
if np.any(a):
index = np.argmax(a) + 1
print(index)