列表的最小值和最大值(不使用 min/max 函数)

Posted

技术标签:

【中文标题】列表的最小值和最大值(不使用 min/max 函数)【英文标题】:Min and Max of a List (without using min/max function) 【发布时间】:2013-02-15 09:48:32 【问题描述】:

我想知道是否有一种方法可以在不使用 Python 中的 min/max 函数的情况下找到列表的 min 和 max。所以我用递归写了一个小代码。我的逻辑非常幼稚:我制作了两个堆栈(min_stackmax_stack),它们在每次递归调用期间跟踪最小值和最大值。我有两个问题:

    谁能帮我估计一下我的代码的复杂性? 有没有更好的方法来做到这一点?使用 mergesort/quicksort 对列表进行排序并选择第一个和最后一个元素会带来更好的性能吗?

这是我在 Python 中的尝试:

minimum = []
maximum = []

# Defining Stack Class
class Stack:
    def __init__(self) :
        self.items = []

    def push(self, item) :
        self.items.append(item)

    def pop(self) :
        return self.items.pop()

    def access(self, index):
        return self.items[index]

    def isEmpty(self) :
        return (self.items == [])

    def length(self):
        return len(self.items)

def minmax(input_list):
    # make two stacks, one for min and one for max
    min_stack = Stack()
    max_stack = Stack()
    # comparing the first two elements of the list and putting them in appropriate stack
    if input_list[0]<input_list[1]:
        min_stack.push(input_list[0])
        max_stack.push(input_list[1])
    else:
        max_stack.push(input_list[0])
        min_stack.push(input_list[1])

    # Pushing remaining elements of the list into appropriate stacks. 
    for i in range(2, len(input_list)):
        if input_list[i] < min_stack.access(-1):
            min_stack.push(input_list[i])
        else:
            max_stack.push(input_list[i])

    # to find minimum
    minlist = []
    while min_stack.length() > 0:
        minlist.append(min_stack.pop())

    # to find maximum
    maxlist = []
    while max_stack.length() > 0:
        maxlist.append(max_stack.pop())

    if len(minlist) > 1:
        minmax(minlist)
    else:
        minimum.append(minlist)


    if len(maxlist) > 1:
        minmax(maxlist)
    else:
        maximum.append(maxlist)

def main():
    input_list = [2, 0, 2, 7, 5, -1, -2]
    print 'Input List is: ', input_list
    minmax(input_list)

print 'Global Minimum is: ', minimum[0]
print 'Global Maximum is: ', maximum[len(maximum)-1]

if __name__ == "__main__":
    main()

【问题讨论】:

哇...这看起来真的太复杂了... 我认为使用 sorted 并采用 0 和 -1 索引会更快......并且更具可读性a = sorted(my_list);min,max=a[0],a[-1]; 如果我是一名面试官并问了这个问题......递给我的候选人在你所拥有的不会得到这份工作...... @mgilson:是的......它很复杂,因为我被要求使用 Stacks 作为一种锻炼方式来实现它。 啊,如果你被明确要求使用堆栈,那么也许......(虽然我不确定为什么有人会想要......) @JoranBeasley:我不确定排序是否是最好的方法。但感谢您的评论。 【参考方案1】:

使用sorted() 当然对于中等大小的列表来说是可靠的、快速编写的和高性能的,因为它是内置的。对于大型列表,O(n) 算法会更快,例如:

def minmax1 (x):
    # this function fails if the list length is 0 
    minimum = maximum = x[0]
    for i in x[1:]:
        if i < minimum: 
            minimum = i 
        else: 
            if i > maximum: maximum = i
    return (minimum,maximum)

print(minmax1([9,8,7,6,5,4,3,2,1,11,12,13,14,15,16,17,18,19]))
print(minmax1([1]))
print(minmax1([2, 0, 2, 7, 5, -1, -2]))

... 其输出为:

(1, 19)
(1, 1)
(-2, 7)

我有兴趣检查这两种替代方案的性能。在我运行 Windows XP 和 Python 3.2.3 的 PC 上,我发现排序方法比上面为少于 500 个元素的列表定义的 minmax1() 函数更快,但是对于更长的列表,O(n) minmax1() 是快点。我的计时测试代码如下:

def minmax_sort(x):
    x = sorted(x)
    return (x[0],x[-1])

import timeit

aa = list(range(0,100))
a = aa
while (1):
    stime = min(timeit.repeat('minmax_sort(a)', "from __main__ import minmax_sort,a",number=1000))
    mtime = min(timeit.repeat('minmax1(a)', "from __main__ import minmax,a",number=1000))
    if (stime > mtime):
        break
    else:
        a = a + aa
print(len(a))

【讨论】:

感谢您比较这两种方法。我想我使用递归和堆栈的方法对于这样的问题来说是复杂且过度的。 请注意,使用 return min(x),max(x) 开始成为具有 300 个或更多元素的列表以及示例列表和随机列表的最快方法。 我认为更现实的测试是编写一个函数,该函数接受一个可选的 key 关键字参数,该参数指定一个参数的函数,该参数将用于提取每个元素的比较键,然后将其与使用相同 key= 函数的内置 sorted() 函数进行比较。【参考方案2】:

仅使用递归查找列表的最小值和最大值。

上周我有类似的任务,我将代码分为三个部分。

第 1 步:查找列表中的最小值

def RecursiveMin(L):
if len(L)==2:
    if L[0]<L[1]:
        return L[0]
    else:
        return L[1]
else:
    X= RecursiveMin(L[1:])
    if L[0]<X:
        return L[0]
    else:
        return X

第 2 步:使用升序对列表进行排序(从小到大)

def Sort(x):
L=sorted(x)
if x==L:
    return x
else:
    i=0
    for i in range (len(x)):
        if x[i] > x[i+1] :
            break

    unsortedPart = x[i:]
    R = RecursiveMin(unsortedPart)
    I = unsortedPart.index(R)

    for j in range (len(x)):
        if x[j] > R :
            del x[(I+i)]
            x.insert(j,R)
            break

    return Sort(x)

(我之前回答了一个排序列表问题并提供了相同的代码。所以请不要标记我抄袭,因为这是我自己的代码 链接:Finding minimum element in a list (recursively) - Python)。

**第 3 步:创建一个带有参数的新函数,无论用户想要最小值还是最大值*

def minMax(lst,user):
    if user == min:
       return Sort(lst)
    elif user == max:
       s = Sort(lst)
       return s[::-1]

最后一步不是递归的,但如果将所有三个步骤编译成一个函数,它将是“1 个递归函数”。 PS 如果您的问题只是关于在列表中查找最小值和最大值,您可以跳过 Step 2 并对 Step 1Step 3

【讨论】:

【参考方案3】:

这将非常简单易懂。希望这会对你有所帮助。

arr = []
num = int(input("Enter number of elements in list: ")) 
for i in range(0, num): 
    ele = int(input("Enter elements: ")) 
    arr.append(ele)

min = arr[ 0 ]
for a in arr:
    if a < min:
        min = a
print ("The minimum number in the list is: ", min)

max = arr[0]
for a in arr:
    if a > max:
        max = a
print("The maximum number in the lit is: ", max)

【讨论】:

欢迎来到 SO!当你主要用代码回答问题时,尽量解释它,最多在有其他答案时,所以你应该展示你的优点。【参考方案4】:

我被要求使用 Stacks 作为一种锻炼方式来实现它。

我很惊讶有几个解决方案需要多次通过列表来确定最小值和最大值。这是一个简单的 Python 3 递归解决方案,每个 OP 使用 stacks,它只通过列表:

def minmax(array, minimum=None, maximum=None):

    head, *tail = array

    if minimum is None:
        minimum = [head]
    elif head < minimum[-1]:
        minimum.append(head)

    if maximum is None:
        maximum = [head]
    elif head > maximum[-1]:
        maximum.append(head)

    if tail:
        return minmax(tail, minimum, maximum)

    return minimum.pop(), maximum.pop()

if __name__ == "__main__":

    array = [2, 0, 2, 7, 5, -1, -2]
    minimum, maximum = minmax(array)
    print(array, minimum, maximum)

    array = [13]
    minimum, maximum = minmax(array)
    print(array, minimum, maximum)

    array = [9, 8, 7, 6, 5, 4, 3, 2, 1, 11, 12, 13, 14, 15, 16, 17, 18, 19]
    minimum, maximum = minmax(array)
    print(array, minimum, maximum)

虽然堆栈对于此代码的工作并不是绝对必要的。

【讨论】:

【参考方案5】:

为了找到最大值,我们可以使用以下逻辑:

def mx(y):
    max_n = y[0] # initial the max to the first element

for i in range(len(y)-1): # for every element check if its greater than max.
    if y[i+1]>max_n:
        max_n = y[i+1] # if so, assign max to the value
return(max_n) 
      

【讨论】:

【参考方案6】:

如果你使用 sorted() 函数,只需调用第一个索引作为最小值,最后一个索引作为最大值。不需要 for 循环。

def minimum(x):
    x = sorted(x)
    return x[0]

def maximum(x):
    x = sorted(x)
    return x[-1]

print(minimum([2, -5, 79, 20, -67])
print(maximum([45, -78, 950, 39, -567])

输出是:

-67
950

【讨论】:

【参考方案7】:
def inIntervalle(liste, min, max):
    liste_intervalle = []
    for i in range(len(liste)):
        if liste[i] < max and liste[i] > min:
            liste_intervalle.append(liste[i])
    return liste_intervalle 

【讨论】:

我看到未注释的代码使用的参数是问题中提供的参数的三倍。据我所知,它与Min and Max of a List in Python 的唯一关系是出现的每个大写术语。这篇文章未能回答 Prakhar Mehrotra 提出的每一个带有编号的明确问题。【参考方案8】:

这是一个使用递归函数的简单解决方案。 让arr 成为您的号码列表。可以通过到达列表末尾并一次比较最后 2 个数字并将结果传播回上一个函数调用,一直到第一个元素,来找出最小值/最大值。

def get_min_max(arr):
    min = find_peak(arr, peak = "minimum")
    max = find_peak(arr, peak = "maximum")
    return "minimum": min, "maximum": max

def find_peak(arr, peak):
    if len(arr) == 1: # base condition
        return arr[0]    
    n1 = arr[0]
    n2 = find_peak(arr[1:], peak) # first element removed for each call
    if peak == "maximum":
        if n1 > n2: 
            return n1
        else:
            return n2
    else:
        if n1 < n2: 
            return n1
        else:
            return n2

【讨论】:

请注意,问题询问如何找到最大值最小值:它要求两者。 @greybeard 修改代码以返回最小值和最大值 (我看到代码返回 either,可选择的。参见 Simon's answer 返回两者。)【参考方案9】:
min=99999999999999
while True:
    value=int(input('enter your values:'))
    if value==333: #enter 333 to end the input
        break
    if min>value:
        min=value
print(min)  

【讨论】:

以上是关于列表的最小值和最大值(不使用 min/max 函数)的主要内容,如果未能解决你的问题,请参考以下文章

方案括号

使用 where min/max laravel 获取所有行

python循环输入若干个同学的成绩,求出这些同学的成绩平均值、最小值和最大值?

关于NOMINMAX这个预处理宏

优化查询以确定一个值在最小值和最大值之间

跨字段选择最小值和最大值并按用户聚合