在递减然后递增并且可能包含重复项的列表中查找最小值
Posted
技术标签:
【中文标题】在递减然后递增并且可能包含重复项的列表中查找最小值【英文标题】:Finding the minimum in a list that is Decreasing and then Increasing and might contain duplicates 【发布时间】:2019-03-19 11:24:54 【问题描述】:给定一个可以分成两部分 L[:z] 和 L[z:] 的列表,其中第一个不增加,第二个不减少并且可能包含或不包含重复元素,创建一个函数使得:
输入:
上面指定的列表 L 值 k 表示任何给定值在列表中重复的最大次数输出:
列表的最小值复杂性和要求
O(log n) 只能使用不包括 min/max 的内置库函数我有以下几点:
def findmin(L, k = None):
left = 0
right = len(L)-1
foundmin = False
while not foundmin:
mp = (left + right)//2
if L[mp] > L[mp+1]:
left = mp
elif L[mp-1] < L[mp]:
right = mp+1
else:
return L[mp]
它仅适用于某些列表,例如: L = [9,9,4,3,2,1,7,7,10,10]
但它不适用于以下列表: L = [6,5,4,3,3,3,3,3,3,3,3,3,1,7,7,7,7]
我尝试修改函数以适应重复的元素,但无济于事。我也没有看到输入 k 对函数的效用。想法?
【问题讨论】:
你为什么不使用min(L)
。它为您提供列表中的最小值。您可以将列表划分为n
数字,然后在将这些n
值添加到列表后进行比较。
@ShivkumarBirnale 因为问题的请求时间复杂度是 O(logn) 并且 min(L)
运行在 O(n) 中
@ShivkumarBirnale 我正在尝试学习如何在不过度依赖库函数的情况下使用列表。此外,最小/最大的复杂度是 O(n),这对我的应用程序不起作用。
二进制搜索就是答案。但是您可能应该检查数组的边界元素,因为这是找到循环移位排序数组的移位点的解决方案,并且您的问题的输入表明两者在本质上非常相似。另外,考虑以某种方式使用 K 的值?
@coldspeed 我尝试使用 k 按顺序比较列表中的 k+1 个值,但这只会导致更多的复杂性。我认为这个想法是检查大小为 k+1 的子集,直到找到一个既增加又减少的子集,然后您就会知道最小值在该子集中,您可以从那里缩小范围。
【参考方案1】:
您的解决方案的问题是,如果 mp 两边的数字等于 mp,那么您的算法将输出 L[mp]。因此,在第二种情况下,它输出 3。一个简单的事情是检查下一个不相等的数字,而不是只检查相邻的数字。
修改方案:
def findmin(L, k = None):
left = 0
right = len(L)-1
foundmin = False
while left<right:
print(left, right)
mp = (left + right)//2
next_diff = mp+1
while(next_diff < len(L)-1 and L[next_diff] == L[mp]):
next_diff+=1
if L[mp] > L[next_diff]:
left = next_diff
elif L[mp] <= L[next_diff]:
right = mp
return L[left]
P.S : 虽然这种情况下的复杂度变成了 O(k* log n)。
【讨论】:
这似乎是正确的,适用于两个列表。我现在通过尝试仅检查相邻值来了解我哪里出错了。根据我对大 O 表示法的理解,常量会被丢弃,所以无论如何都会变成 O(log n)。 @Devon_Letendre,很高兴它有帮助。是的,如果你认为它是一个常数,它就会被丢弃。因为,您提到您希望它作为输入,所以通常作为输入的参数不被视为常量。请考虑投票和/或接受。【参考方案2】:此代码在 O(logn) 中运行,并且没有使用 k
参数。
这是某种二进制搜索,如 @coldspeed 所评论的。
def find_min(l, k=None):
left = 0
right = len(l) - 1
while left <= right:
middle = (left + right) // 2
if l[middle] < l[left] or (l[middle] == l[left] and middle > left):
left = middle
elif l[middle] < l[right] or (l[middle] == l[right] and middle < right):
right = middle
else:
return l[middle]
【讨论】:
以上是关于在递减然后递增并且可能包含重复项的列表中查找最小值的主要内容,如果未能解决你的问题,请参考以下文章