54

我正在学习 Python,处理列表的简单方法被认为是一个优势。有时是这样,但看看这个:

>>> numbers = [20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7]
>>> numbers.remove(max(numbers))
>>> max(numbers)
74

从列表中获取第二大数字的一种非常简单、快速的方法。除了简单的列表处理有助于编写一个在列表中运行两次的程序,找到最大的然后是第二大的。这也是破坏性的 - 如果我想保留原始数据,我需要两份数据副本。我们需要:

>>> numbers = [20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7]
>>> if numbers[0]>numbers[1]):
...    m, m2 = numbers[0], numbers[1]
... else:
...    m, m2 = numbers[1], numbers[0]
...
>>> for x in numbers[2:]:
...    if x>m2:
...       if x>m:
...          m2, m = m, x
...       else:
...          m2 = x
...
>>> m2
74

它仅在列表中运行一次,但不像以前的解决方案那样简洁明了。

那么:在这种情况下,有没有办法两者兼得?第一个版本的清晰度,但第二个版本的单曲贯穿?

4

31 回答 31

74

您可以使用heapq模块:

>>> el = [20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7]
>>> import heapq
>>> heapq.nlargest(2, el)
[90.8, 74]

然后从那里走...

于 2013-04-25T22:23:22.670 回答
36

由于@OscarLopez 和我对第二大的含义有不同的看法,所以我将根据我的解释并根据提问者提供的第一个算法发布代码。

def second_largest(numbers):
    count = 0
    m1 = m2 = float('-inf')
    for x in numbers:
        count += 1
        if x > m2:
            if x >= m1:
                m1, m2 = x, m1            
            else:
                m2 = x
    return m2 if count >= 2 else None

(注意:这里使用负无穷大而不是None因为None在 Python 2 和 3 中具有不同的排序行为 - 请参阅Python - Find second minimum number;检查元素的数量以numbers确保在实际使用负无穷大时不会返回负无穷大答案未定义。)

如果最大值出现多次,它也可能是第二大的。这种方法的另一件事是,如果元素少于两个,它就可以正常工作。那么就没有第二大了。

运行相同的测试:

second_largest([20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7])
=> 74
second_largest([1,1,1,1,1,2])
=> 1
second_largest([2,2,2,2,2,1])
=> 2
second_largest([10,7,10])
=> 10
second_largest([1,1,1,1,1,1])
=> 1
second_largest([1])
=> None
second_largest([])
=> None

更新

我重组了条件以显着提高性能;在我对随机数的测试中几乎 100%。这样做的原因是在原始版本中,elif总是在下一个数字不是列表中最大的情况下评估。换句话说,对于列表中的几乎每个数字,都进行了两次比较,而一次比较就足够了——如果数字不大于第二大,它也不大于最大的。

于 2013-04-25T23:15:50.393 回答
25

你总是可以使用sorted

>>> sorted(numbers)[-2]
74
于 2013-04-25T22:21:54.183 回答
20

试试下面的解决方案,O(n)它会存储并返回second变量中的第二大数字。更新:我已经调整了代码以使用 Python 3,因为现在算术比较None无效。

请注意,如果其中的所有元素numbers都相等,或者如果numbers为空或包含单个元素,则该变量second最终的值为None- 这是正确的,因为在这些情况下没有“第二大”元素。

注意:这会找到“第二个最大值”值,如果有多个值是“第一个最大值”,它们都将被视为相同的最大值 - 在我的定义中,在这样的列表中:[10, 7, 10]正确答案是7.

def second_largest(numbers):
    minimum = float('-inf')
    first, second = minimum, minimum
    for n in numbers:
        if n > first:
            first, second = n, first
        elif first > n > second:
            second = n
    return second if second != minimum else None

以下是一些测试:

second_largest([20, 67, 3, 2.6, 7, 74, 2.8, 90.8, 52.8, 4, 3, 2, 5, 7])
=> 74
second_largest([1, 1, 1, 1, 1, 2])
=> 1
second_largest([2, 2, 2, 2, 2, 1])
=> 1
second_largest([10, 7, 10])
=> 7
second_largest( [1, 3, 10, 16])
=> 10
second_largest([1, 1, 1, 1, 1, 1])
=> None
second_largest([1])
=> None
second_largest([])
=> None
于 2013-04-25T22:51:51.977 回答
7

为什么要把剧情复杂化?它非常简单直接

  1. 将列表转换为集合 - 删除重复项
  2. 再次将集合转换为列表 - 以升序给出列表

这是一个代码

mlist = [2, 3, 6, 6, 5]
mlist = list(set(mlist))
print mlist[-2]
于 2016-11-07T07:36:26.407 回答
5

您可以通过以下任何一种方式找到第二大的:

选项1:

numbers = set(numbers)
numbers.remove(max(numbers))
max(numbers)

选项 2:

sorted(set(numbers))[-2]
于 2018-07-12T16:12:29.153 回答
4

快速选择算法,快速排序的O(n) 表亲,会做你想做的事。快速选择的平均性能为 O(n)。最坏情况的性能是 O(n^2),就像快速排序一样,但这种情况很少见,并且对快速选择的修改将最坏情况的性能降低到 O(n)。

快速选择的思想是使用相同的枢轴、较低、较高的快速排序思想,但随后忽略较低的部分并仅对较高的部分进行进一步排序。

于 2015-06-13T18:36:17.853 回答
2

如果您不介意使用 numpy ( import numpy as np):

np.partition(numbers, -2)[-2]

为您提供列表中第二大元素,保证最坏情况O(n)运行时间

这些partition(a, kth)方法返回一个数组,其中第kth 个元素与排序数组中的相同,前面的所有元素都较小,后面的所有元素都较大。

于 2017-04-02T17:03:35.640 回答
2

这是简单方法之一

def find_second_largest(arr):
    first, second = 0, 0

    for number in arr:
        if number > first:
            second = first
            first = number
        elif number > second and number < first:
            second = number

    return second
于 2021-10-19T11:58:58.580 回答
1

这里有一些关于 type([]) 的好答案,以防有人在 type({}) 上需要同样的东西,

def secondLargest(D):
    def second_largest(L):  
        if(len(L)<2):
            raise Exception("Second_Of_One")
        KFL=None #KeyForLargest
        KFS=None #KeyForSecondLargest
        n = 0
        for k in L:
            if(KFL == None or k>=L[KFL]):
                KFS = KFL
                KFL = n
            elif(KFS == None or k>=L[KFS]):
                KFS = n
            n+=1
        return (KFS)
    KFL=None #KeyForLargest
    KFS=None #KeyForSecondLargest
    if(len(D)<2):
        raise Exception("Second_Of_One")
    if(type(D)!=type({})):
        if(type(D)==type([])):
            return(second_largest(D))
        else:
            raise Exception("TypeError")
    else:
        for k in D:
            if(KFL == None or D[k]>=D[KFL]):
                KFS = KFL               
                KFL = k
            elif(KFS == None or D[k] >= D[KFS]):
                KFS = k
    return(KFS)

a = {'one':1 , 'two': 2 , 'thirty':30}
b = [30,1,2] 
print(a[secondLargest(a)])
print(b[secondLargest(b)])

只是为了好玩,我试图让它对用户友好 xD

于 2015-01-13T16:24:21.213 回答
1
>>> l = [19, 1, 2, 3, 4, 20, 20]
>>> sorted(set(l))[-2]
19
于 2015-07-21T22:52:19.150 回答
1

O(n):如果循环变量以恒定量递增/递减,则循环的时间复杂度被视为 O(n)。例如以下函数具有 O(n) 时间复杂度。

 // Here c is a positive integer constant   
   for (int i = 1; i <= n; i += c) {  
        // some O(1) expressions
   }

为了找到第二大的数字,我使用下面的方法首先找到最大的数字,然后搜索列表是否在里面

x = [1,2,3]
A = list(map(int, x))
y = max(A)
k1 = list()
for values in range(len(A)):
if y !=A[values]:
    k.append(A[values])

z = max(k1)
print z
于 2016-08-02T06:27:48.197 回答
1

这可以在 [N + log(N) - 2] 时间内完成,这比 2N 的宽松上限(也可以认为是 O(N))略好。

诀窍是使用二进制递归调用和“网球锦标赛”算法。获胜者(人数最多)将在所有“比赛”之后出现(需要 N-1 次),但如果我们记录所有比赛的“玩家”,并在其中将获胜者击败的所有玩家分组,第二大数字将是该组中最大的数字,即“失败者”组。

这个“失败者”组的大小是 log(N),同样,我们可以撤销二进制递归调用以在失败者中找到最大的,这将花费 [log(N) - 1] 时间。实际上,我们也可以线性扫描失败者组来得到答案,时间预算是一样的。

下面是一个示例 python 代码:

def largest(L):
    global paris
    if len(L) == 1:
        return L[0]
    else:
        left = largest(L[:len(L)//2])
        right = largest(L[len(L)//2:])
        pairs.append((left, right))
        return max(left, right)

def second_largest(L):
    global pairs
    biggest = largest(L)
    second_L = [min(item) for item in pairs if biggest in item]

    return biggest, largest(second_L)  



if __name__ == "__main__":
    pairs = []
    # test array
    L = [2,-2,10,5,4,3,1,2,90,-98,53,45,23,56,432]    

    if len(L) == 0:
        first, second = None, None
    elif len(L) == 1:
        first, second = L[0], None
    else:
        first, second = second_largest(L)

    print('The largest number is: ' + str(first))
    print('The 2nd largest number is: ' + str(second))
于 2016-09-29T05:47:25.503 回答
1

目标:从输入中找到第二大的数字。

输入:5 2 3 6 6 5

输出:5

*n = int(raw_input())
arr = map(int, raw_input().split())
print sorted(list(set(arr)))[-2]*
于 2017-10-24T08:14:54.747 回答
1
    def SecondLargest(x):
        largest = max(x[0],x[1])
        largest2 = min(x[0],x[1])
        for item in x:
            if item > largest:
               largest2 = largest
               largest = item
            elif largest2 < item and item < largest:
               largest2 = item
        return largest2
    SecondLargest([20,67,3,2.6,7,74,2.8,90.8,52.8,4,3,2,5,7])
于 2018-04-30T22:33:17.407 回答
1
list_nums = [1, 2, 6, 6, 5]
minimum = float('-inf')
max, min = minimum, minimum
for num in list_nums:
    if num > max:
        max, min = num, max
    elif max > num > min:
        min = num
print(min if min != minimum else None)

输出

5
于 2020-05-12T12:55:59.563 回答
1

使用 -inf 进行初始化。此代码概括了所有情况,以找到第二大元素。

max1= float("-inf")
max2=max1
for item in arr:
    if max1<item:
        max2,max1=max1,item
    elif item>max2 and item!=max1:
        max2=item
print(max2)
于 2021-09-30T19:56:39.743 回答
0

你也可以试试这个:

>>> list=[20, 20, 19, 4, 3, 2, 1,100,200,100]
>>> sorted(set(list), key=int, reverse=True)[1]
100
于 2016-10-24T05:54:14.350 回答
0

一个简单的方法:

n=int(input())
arr = set(map(int, input().split()))
arr.remove(max(arr))
print (max(arr))
于 2017-12-18T15:41:12.160 回答
0

使用默认的 sort()方法获取列表中的第二大数字。排序是内置方法,您不需要为此导入模块。

lis = [11,52,63,85,14]
lis.sort()
print(lis[len(lis)-2])
于 2018-04-23T12:20:05.050 回答
0

以前的大多数答案都是正确的,但这是另一种方法!

我们的策略是创建一个包含两个变量 first_highest 和 second_highest 的循环。我们循环遍历这些数字,如果我们的 current_value 大于 first_highest,那么我们将 second_highest 设置为与 first_highest 相同,然后将 second_highest 设置为当前数字。如果我们的当前数字大于 second_highest,那么我们将 second_highest 设置为与当前数字相同在此处输入图像描述

#!/usr/bin/env python3
import sys
def find_second_highest(numbers):

    min_integer = -sys.maxsize -1
    first_highest= second_highest = min_integer
    for current_number in numbers:
        if current_number == first_highest and min_integer != second_highest:
            first_highest=current_number
        elif current_number > first_highest:
            second_highest = first_highest
            first_highest = current_number
        elif current_number > second_highest:
            second_highest = current_number
    return second_highest

print(find_second_highest([80,90,100]))
print(find_second_highest([80,80]))
print(find_second_highest([2,3,6,6,5]))
于 2018-11-12T06:42:18.037 回答
0

只是为了使接受的答案更普遍,以下是获得第 k 个最大值的扩展:

def kth_largest(numbers, k):
    largest_ladder = [float('-inf')] * k
    count = 0
    for x in numbers:
        count += 1
        ladder_pos = 1
        for v in largest_ladder:
            if x > v:
                ladder_pos += 1
            else:
                break
        if ladder_pos > 1:
            largest_ladder = largest_ladder[1:ladder_pos] + [x] + largest_ladder[ladder_pos:]
    return largest_ladder[0] if count >= k else None
于 2019-01-09T05:39:00.440 回答
0
def secondlarget(passinput):
    passinputMax = max(passinput)  #find the maximum element from the array
    newpassinput = [i for i in passinput if i != passinputMax]  #Find the second largest element in the array
    #print (newpassinput)
    if len(newpassinput) > 0:
        return max(newpassinput) #return the second largest
    return 0
if __name__ == '__main__':
    n = int(input().strip())  # lets say 5
    passinput = list(map(int, input().rstrip().split())) # 1 2 2 3 3
    result = secondlarget(passinput) #2
    print (result) #2
于 2019-08-19T06:58:03.340 回答
0
if __name__ == '__main__':
    n = int(input())
    arr = list(map(float, input().split()))
    high = max(arr)
    secondhigh = min(arr)
    for x in arr:
        if x < high and x > secondhigh:
            secondhigh = x
    print(secondhigh)

上面的代码是当我们根据用户要求设置列表中的元素值时。下面的代码是根据提出的问题

#list
numbers = [20, 67, 3 ,2.6, 7, 74, 2.8, 90.8, 52.8, 4, 3, 2, 5, 7]
#find the highest element in the list
high = max(numbers)
#find the lowest element in the list
secondhigh = min(numbers)
for x in numbers:
    '''
    find the second highest element in the list,
    it works even when there are duplicates highest element in the list.
    It runs through the entire list finding the next lowest element
    which is less then highest element but greater than lowest element in
    the list set initially. And assign that value to secondhigh variable, so 
    now this variable will have next lowest element in the list. And by end 
    of loop it will have the second highest element in the list  
    '''
    if (x<high and x>secondhigh):
        secondhigh=x
print(secondhigh)
于 2019-10-02T08:38:46.240 回答
0

通过将每个值与 max_item 进行比较来最大化值。在第一个 if 中,每次 max_item 的值发生变化时,它都会将其先前的值赋予 second_max。紧耦合两秒 if 确保边界

def secondmax(self, list):
    max_item = list[0]
    second_max = list[1]
    for item in list:
        if item > max_item:
            second_max =  max_item
            max_item = item
        if max_item < second_max:
            max_item = second_max
    return second_max
于 2019-12-25T12:31:31.297 回答
0

您必须在新值之间进行比较,这就是诀窍,始终认为前一个(第二大)应该在最大值和前一个最大值之间,就是那个!!!!

def secondLargest(lista):
    max_number   = 0
    prev_number  = 0

    for i in range(0, len(lista)):

        if lista[i] > max_number:
            prev_number = max_number
            max_number  = lista[i]
        elif lista[i] > prev_number and lista[i] < max_number:
            prev_number = lista[i]

    return prev_number
于 2020-03-06T16:47:28.200 回答
0

我的朋友 Dhanush Kumar 提出的最佳解决方案:

    def second_max(loop):
        glo_max = loop[0]
        sec_max = float("-inf")
        for i in loop:
            if i > glo_max:
                sec_max = glo_max
                glo_max=i
            elif sec_max < i < glo_max:
                sec_max = i
        return sec_max
    
    #print(second_max([-1,-3,-4,-5,-7]))
    
    assert second_max([-1,-3,-4,-5,-7])==-3
    assert second_max([5,3,5,1,2]) == 3
    assert second_max([1,2,3,4,5,7]) ==5
    assert second_max([-3,1,2,5,-2,3,4]) == 4
    assert second_max([-3,-2,5,-1,0]) == 0
    assert second_max([0,0,0,1,0]) == 0
于 2020-11-05T13:46:28.667 回答
0

下面的代码将在不使用 max 函数的情况下找到最大值和第二个最大值。我假设输入将是数字,并且数字由单个空格分隔。

myList = input().split()
myList = list(map(eval,myList))


m1 = myList[0]
m2 = myList[0]

for x in myList:
    if x > m1:
        m2 = m1
        m1 = x
    elif x > m2:
        m2 = x

print ('Max Number: ',m1)
print ('2nd Max Number: ',m2)
于 2021-02-06T17:22:45.360 回答
0

在这里,我试图想出一个答案。使用单循环且不使用任何内置函数的列表中的第二(第二)个最大元素。

def secondLargest(lst):
    mx = 0
    num = 0
    sec = 0
    for i in lst:
        if i > mx:
            sec = mx
            mx = i
        else:
            if i > num and num >= sec:
                sec = i
            num = i
    return sec
于 2021-04-22T11:27:02.727 回答
0

我们可以使用 2 循环来比较并从列表中找到第二大数字,而不是从列表中删除最大数字:

def second_largest(list1):
   second_max = list1[0]
   max_nu = max(list1)

   for i in range(len(list1) -1):
       for j in range(1,len(list1)):
          if list1[i] > list1[j] and list1[i] < max_nu :
              second_max = list1[i]
          elif list1[i] < list1[j] and list1[j] < max_nu:
              second_max = list1[j]
   return second_max

l = [2, 4, 5, 6, 8, 7, 21, 20]
print(second_largest(l))
于 2021-11-17T08:09:09.137 回答
-1
n=input("Enter a list:")
n.sort()
l=len(n)
n.remove(n[l-1])
l=len(n)
print n[l-1]
于 2015-11-15T02:21:17.493 回答