在Python 3
中,如何有效地从整数列表中获取最多m个元素和最后m个元素n次(省略先前的最大值)?
说
arr=[10,20,35,30,10,45,0,20,25,50,15]
m=4
n=3
1<=array size<=10^5
0<=array element<=10^9
1<=n<=array size
1<=m<=array size
First m elements = [10,20,35,30]
Last m elements = [20,25,50,15]
0th element of the output list --> maximum of above i.e. 50
after omitting 50
arr=[10,20,35,30,10,45,0,20,25,15]
First m elements = [10,20,35,30]
Last m elements = [0,20,25,15]
1th element of the output list --> maximum of above i.e. 35
and so on... upto (n-1)th element
我尝试使用基本逻辑,并且它对小输入工作正常,但是因为列表大小得到超时错误,m,n可以高达10 ^ 5。是否有任何python特定的快捷方式来有效地实现它?
代码#1
for i in range(0,n):
if len(arr)>2*m+n-i-1:
temp=arr[:m]+arr[-m:]
else:
temp=arr
x=max(temp)
ind=temp.index(x)
if ind>=m:
ind=ind-len(temp)
arr.pop(ind)
print(x)
代码#2
l=len(arr)
for j in range(0,n):
acnt=0
bcnt=0
ai=0
bi=-1
x=-1
while acnt<m and ai<l:
if arr[ai]!=-1:
if arr[ai]>x:
x=arr[ai]
i=ai
acnt=acnt+1
ai=ai+1
while bcnt<m and bi>=-l:
if arr[bi]!=-1:
if arr[bi]>x:
x=arr[bi]
i=bi
bcnt=bcnt+1
bi=bi-1
print(x)
arr[i]=-1
此外,我尝试使用递归和排序,但我仍然遇到大型测试用例的超时错误。还有其他解决方案复杂性较低吗?
答案 0 :(得分:0)
m = 4
n = 3
arr = [10,20,35,30,10,45,0,20,25,50,15]
# From Start
for x in range(n):
maximum = max(arr[:m])
arr.remove(maximum);
print(maximum)
arr = [10,20,35,30,10,45,0,20,25,50,15]
# From End
for x in range(n):
maximum = max(arr[m+1:])
arr.remove(maximum);
print(maximum)
将列表切片到第m个元素并取其最大值,然后从初始列表中删除第一个匹配项。
由于它从数组中删除了最大元素并假设这些范围可能重叠,因此需要初始化初始数组两次。除非你知道它们不会重叠。
或者如果目标是从开头到结尾依次采取最大值,那么可以很容易地将其修改为:
m=4
n=3
arr=[10,20,35,30,10,45,0,20,25,50,15]
for x in range(n):
maximum = max(arr[m+1:]) # From End
arr.remove(maximum);
print(maximum)
maximum = max(arr[:m]) # From Start
arr.remove(maximum);
print(maximum)
显然可能有更好的解决方案。
您可以通过使用某种记忆和动态编程来加速该过程。按排序顺序跟踪子数组值,以便轻松访问下一个最大值,并且只能逐个添加/删除它们。
或创建一些自定义数据结构以跟踪本地最大值。
答案 1 :(得分:0)
完整的实施可能如下所示:
import itertools
def f(array, m, n):
l = len(array)
if l <= 2 * m: # The full array fits in the first iteration
temp = sorted(array)
for i in range(-1, -min(n,l)-1, -1):
yield temp[i]
else:
i = m # Next element from the start
j = l - m - 1 # Next element from the end
temp = [(array[k], k) for k in itertools.chain(range(i), range(j + 1, l))]
for _ in range(n):
temp.sort()
max, index = temp[-1]
yield max
if i > j: # Check that we haven't crossed the indexes
break
if index < i:
temp[-1] = (array[i], i)
i += 1
else:
temp[-1] = (array[j], j)
j -= 1
# Usage
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=4, n= 3)))
# [50, 35, 30]
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=4, n= 4)))
# [50, 35, 30, 45]
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=4, n=10)))
# [50, 35, 30, 45]
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=4, n=12)))
# [50, 35, 30, 45]
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=10, n= 3)))
# [50, 45, 35]
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=10, n= 4)))
# [50, 45, 35, 30]
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=10, n=10)))
# [50, 45, 35, 30, 25, 20, 20, 15, 10, 10]
print(list(f([10, 20, 35, 30, 10, 45, 0, 20, 25, 50, 15], m=10, n=12)))
# [50, 45, 35, 30, 25, 20, 20, 15, 10, 10, 0]
答案 2 :(得分:0)
最后删除额外的循环开销,它适用于所有测试用例。谢谢你的帮助。
f=0
r=len(arr)-1
f_flag=1
r_flag=1
for i in range(0,n):
if r<=f+2*m-1:
arr[f:r+1]=sorted(arr[f:r+1],reverse=True)
f=f+n-i
break
else:
for j in range(0,m-1):
if f_flag==1:
if f+j+1<len(arr):
if arr[f]<arr[f+j+1]:
x=arr[f]
arr[f]=arr[f+j+1]
arr[f+j+1]=x
if r_flag==1:
if r-1-j>=0:
if arr[r]<arr[r-1-j]:
x=arr[r]
arr[r]=arr[r-1-j]
arr[r-1-j]=x
if arr[f]>=arr[r]:
f=f+1
f_flag=1
r_flag=0
else:
r=r-1
f_flag=0
r_flag=1
return(sum(arr[:f]+arr[r+1:]))