Python 给定一个包含 N 个整数的数组 A,返回在 O(n) 时间复杂度内不会出现在 A 中的最小正整数(大于 0)
Posted
技术标签:
【中文标题】Python 给定一个包含 N 个整数的数组 A,返回在 O(n) 时间复杂度内不会出现在 A 中的最小正整数(大于 0)【英文标题】:Python given an array A of N integers, returns the smallest positive integer (greater than 0) that does not occur in A in O(n) time complexity 【发布时间】:2018-08-19 19:28:40 【问题描述】:例如:
输入:A = [ 6 4 3 -5 0 2 -7 1 ]
输出:5
因为 5 是未出现在数组中的最小正整数。
我已经为这个问题写了两个解决方案。第一个很好,但我不想使用任何外部库 + 它的 O(n)*log(n) 复杂性。当输入是混沌序列长度=10005(带减号)时,第二种解决方案“我需要你的帮助来优化它”会出错。
解决方案 1:
from itertools import count, filterfalse
def minpositive(a):
return(next(filterfalse(set(a).__contains__, count(1))))
解决方案 2:
def minpositive(a):
count = 0
b = list(set([i for i in a if i>0]))
if min(b, default = 0) > 1 or min(b, default = 0) == 0 :
min_val = 1
else:
min_val = min([b[i-1]+1 for i, x in enumerate(b) if x - b[i - 1] >1], default=b[-1]+1)
return min_val
注意:这是一个关于 codility 的演示测试,解决方案 1 获得了 100% 和 解决方案 2 得到了 77 %。 “解决方案 2”中的错误是由于: 性能测试-> 中等混沌序列长度 = 10005(带减号)预期为 3 10000 性能测试 -> large chaotic + many -1, 1, 2, 3 (with 减)得到 5 预期 10000
【问题讨论】:
我认为您假设list(set(a))
已排序,但事实并非如此。不清楚你在问什么——你是在问工作代码吗?
两者都在工作,但我正在寻找一种方法来优化该代码以使用 O(n) 时间复杂度“如我的问题所述”。
感谢Paul 的提示“我认为您正在假设 list(set(a)) ”。它不会影响我的第二个代码。我以后会用 sorted。
这是来自codility.com的演示任务:)
【参考方案1】:
def minpositive(A):
"""Given an list A of N integers,
returns the smallest positive integer (greater than 0)
that does not occur in A in O(n) time complexity
Args:
A: list of integers
Returns:
integer: smallest positive integer
e.g:
A = [1,2,3]
smallest_positive_int = 4
"""
len_nrs_list = len(A)
N = set(range(1, len_nrs_list+2))
return min(N-set(A)) #gets the min value using the N integers
【讨论】:
如果你以N = set(range(1, len_nrc_list+2))
开头,你可以摆脱try/except。【参考方案2】:
def solution(A):
nw_A = sorted(set(A))
if all(i < 0 for i in nw_A):
return 1
else:
ans = 1
while ans in nw_A:
ans += 1
if ans not in nw_A:
return ans
如果有可能导入 numpy 包,以获得更好的性能。
def solution(A):
import numpy as np
nw_A = np.unique(np.array(A))
if np.all((nw_A < 0)):
return 1
else:
ans = 1
while ans in nw_A:
ans += 1
if ans not in nw_A:
return ans
【讨论】:
每次遇到if
语句时都会调用sorted
吗?另外,是sorted
O(n) 吗?
您将数组排序最多 N 次,因此您的时间复杂度为 O(n^2 * log n),远远超出标准!
谢谢 Calculuswhiz 和 Joanis,我更正了【参考方案3】:
这个问题真的不需要另一个答案,但是有一个尚未提出的解决方案,我相信它比目前提出的解决方案要快。
正如其他人所指出的,我们知道答案在[1, len(A)+1]
范围内,包括在内。我们可以把它变成一个集合,取集合中与 A 差的最小元素。这是一个很好的 O(N) 解决方案,因为集合操作是 O(1)。
但是,我们不需要使用 Python 集来存储 [1, len(A)+1]
,因为我们从密集集开始。我们可以使用数组来代替,它将通过列表索引替换集合散列,并为我们提供另一个具有较低常数的 O(N) 解决方案。
def minpositive(a):
# the "set" of possible answer - values_found[i-1] will tell us whether i is in a
values_found = [False] * (len(a)+1)
# note any values in a in the range [1, len(a)+1] as found
for i in a:
if i > 0 and i <= len(a)+1:
values_found[i-1] = True
# extract the smallest value not found
for i, found in enumerate(values_found):
if not found:
return i+1
我们知道,最终的 for 循环总是会找到一个未标记的值,因为它比 a
多一个元素,所以它的至少一个单元格没有设置为 True
。
【讨论】:
不确定它是否适用于此解决方案,但如果您有一个整数列表,例如:a = [2,3,2],它会返回 2 个值 -> 1, 4 @mseromenho 我不确定你的意思。我刚刚测试了print(minpositive([2,3,2]))
,它给了我1
。
我的错,我错误地测试了代码,我直接从 for 循环打印!很好的解决方案!【参考方案4】:
在比较之前我减少了集合的长度
a=[1,222,3,4,24,5,6,7,8,9,10,15,2,3,3,11,-1]
#a=[1,2,3,6,3]
def sol(a_array):
a_set=set()
b_set=set()
cnt=1
for i in a_array:
#In order to get the greater performance
#Checking if element is greater than length+1
#then it can't be output( our result in solution)
if i<=len(a) and i >=1:
a_set.add(i) # Adding array element in set
b_set.add(cnt) # Adding iterator in set
cnt=cnt+1
b_set=b_set.difference(a_set)
if((len(b_set)) > 1):
return(min(b_set))
else:
return max(a_set)+1
sol(a)
【讨论】:
【参考方案5】:从 Niroj Shrestha 和 najeeb-jebreel 继续,添加了一个初始部分以避免在完整集的情况下进行迭代。如果数组非常大,则尤其重要。
def smallest_positive_int(A):
sorted_A = sorted(A)
last_in_sorted_A = sorted_A[-1]
#check if straight continuous list
if len(sorted_A) == last_in_sorted_A:
return last_in_sorted_A + 1
else:
#incomplete list, iterate to find the smallest missing number
sol=1
for x in sorted_A:
if x == sol:
sol += 1
else:
break
return sol
A = [1,2,7,4,5,6]
print(smallest_positive_int(A))
【讨论】:
如果A中有重复,此解决方案不起作用。【参考方案6】:我刚刚修改了@najeeb-jebreel 的答案,现在该函数给出了最佳解决方案。
def solution(A):
sorted_set = set(sorted(A))
sol = 1
for x in sorted_set:
if x == sol:
sol += 1
else:
break
return sol
【讨论】:
【参考方案7】:def solution(A):
arr = set(A)
N = set(range(1, 100001))
while N in arr:
N += 1
return min(N - arr)
solution([1, 2, 6, 4])
#returns 3
【讨论】:
【参考方案8】:对于大型阵列来说速度很快。
def minpositive(arr):
if 1 not in arr: # protection from error if ( max(arr) < 0 )
return 1
else:
maxArr = max(arr) # find max element in 'arr'
c1 = set(range(2, maxArr+2)) # create array from 2 to max
c2 = c1 - set(arr) # find all positive elements outside the array
return min(c2)
【讨论】:
【参考方案9】:如果 N 的范围是给定的,以下也可以:
N = set(range(1, 100001))
def minpositive(A):
return min(N-set(A))
【讨论】:
您可以假设范围是range(1, len(A)+1)
,因为您确定答案在该范围内,无论 A 中的值如何。【参考方案10】:
def solution(A):
B = set(sorted(A))
m = 1
for x in B:
if x == m:
m+=1
return m
【讨论】:
请提供解释以说明您的代码如何解决问题。 OP 说明这里的时间复杂度应该是线性时间,这里提供的答案是二次时间。 @avizzzy,不是O(n * log n)
吗?如果 sorted
调用被删除,它可能是 O(n)
,毕竟所有集合都是无序的。
Python 集不保留插入项目的顺序,因此该解决方案不应该工作。在实践中,似乎 Python 会针对相当大的最大值对整数集进行排序,但这可能是集合实现方式的结果,现在它是您可以信赖的功能。【参考方案11】:
在 Python 中测试集合中是否存在数字很快,因此您可以尝试以下操作:
def minpositive(a):
A = set(a)
ans = 1
while ans in A:
ans += 1
return ans
【讨论】:
这也会处理给定列表中可能存在的任何重复项。以上是关于Python 给定一个包含 N 个整数的数组 A,返回在 O(n) 时间复杂度内不会出现在 A 中的最小正整数(大于 0)的主要内容,如果未能解决你的问题,请参考以下文章
Python给定一个整数n,将1到n之间的正整数按偶数递增,技术递减的顺序输出?
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
2022-03-06:金币路径。 给定一个数组 A(下标从 1 开始)包含 N 个整数:A1,A2,……,AN 和一个整数 B。 你可以从数组 A 中的任何一个位置(下标为 i)跳到下标 i+1,i+
2021-11-01:寻找重复数。给定一个包含 n + 1 个整数的数组 nums ,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设 nums 只有 一个重复的整数