在最多n + log 2(n)-2比较中找到数组中的第二大数字

时间:2012-03-27 12:39:27

标签: algorithm

您输入一个n个不同数字的未排序数组,其中n是2的幂。给出一个算法,该算法识别数组中第二大的数字,并且最多使用n + log 2(n) - 2比较。

11 个答案:

答案 0 :(得分:37)

  1. 首先比较奇数位和偶数位的n元素数组的元素,并确定每对元素的最大元素。此步骤需要n / 2次比较。现在你只有n / 2个元素。继续成对比较以获得n / 4,n / 8,...元素。找到最大元素时停止。此步骤总共需要n / 2 + n / 4 + n / 8 + ... + 1 = n-1个比较。
  2. 在前一步骤中,立即将最大元素与log 2(n)其他元素进行比较。您可以在log 2(n)-1比较中确定这些元素中最大的元素。这将是数组中第二大的数字。

  3. 示例:8个数字的数组[10,9,5,4,11,100,120,110]。

    第1级比较:[10,9] - > 10 [5,4] - > 5,[11,100] - > 100, [120,110] - > 120。

    第2级比较:[10,5] - > 10 [100,120] - > 120。

    第3级比较: [10,120] - > 120。

    最大值为120.立即与:10(第3级),100(第2级),第110级(第1级)进行比较。

    步骤2应该找到最大值10,100和110.这是110.这是第二大元素。

答案 1 :(得分:2)

我已经用@Evgeny Kluev回答用Java实现了这个算法。总比较为n + log2(n)-2。还有一个很好的参考: http://users.csc.calpoly.edu/~dekhtyar/349-Spring2010/lectures/lec03.349.pdf。这类似于最高投票算法。希望我的解决方案很有用。感谢。

public class op1 {

private static int findSecondRecursive(int n, int[] A){
    int[] firstCompared = findMaxTournament(0, n-1, A); //n-1 comparisons;
    int[] secondCompared = findMaxTournament(2, firstCompared[0]-1, firstCompared); //log2(n)-1 comparisons.
    //Total comparisons: n+log2(n)-2;
    return secondCompared[1];
}

private static int[] findMaxTournament(int low, int high, int[] A){
    if(low == high){
        int[] compared = new int[2];
        compared[0] = 2;
        compared[1] = A[low];
        return compared;
    }
    int[] compared1 = findMaxTournament(low, (low+high)/2, A);
    int[] compared2 = findMaxTournament((low+high)/2+1, high, A);
    if(compared1[1] > compared2[1]){
        int k = compared1[0] + 1;
        int[] newcompared1 = new int[k];
        System.arraycopy(compared1, 0, newcompared1, 0, compared1[0]);
        newcompared1[0] = k;
        newcompared1[k-1] = compared2[1];
        return newcompared1;
    }
    int k = compared2[0] + 1;
    int[] newcompared2 = new int[k];
    System.arraycopy(compared2, 0, newcompared2, 0, compared2[0]);
    newcompared2[0] = k;
    newcompared2[k-1] = compared1[1];
    return newcompared2;
}

private static void printarray(int[] a){
    for(int i:a){
        System.out.print(i + " ");
    }
    System.out.println();
}

public static void main(String[] args) {
    //Demo.
    System.out.println("Origial array: ");
    int[] A = {10,4,5,8,7,2,12,3,1,6,9,11};
    printarray(A);
    int secondMax = findSecondRecursive(A.length,A);
    Arrays.sort(A);
    System.out.println("Sorted array(for check use): ");
    printarray(A);
    System.out.println("Second largest number in A: " + secondMax);
}

}

答案 2 :(得分:1)

问题是: 让我们说,在比较级别1,算法需要记住所有数组元素,因为最大的还不知道,然后,第二,最后,第三。通过分配跟踪这些元素将调用其他值赋值,稍后当知道最大值时,您还需要考虑追溯。结果,它不会比简单的2N-2比较算法快得多。而且,由于代码更复杂,您还需要考虑潜在的调试时间 例如:在PHP中,比较与值分配的运行时间大致为:比较:(11-19)到值赋值:16。

答案 3 :(得分:1)

sly s的answer来自this论文,但是他没有解释算法,这意味着绊脚石这个问题的人必须阅读整篇论文,并且他的代码不是很光滑。我将提供上述论文的算法重点,并进行复杂性分析,并提供一个Scala实现,只是因为这是我在解决这些问题时选择的语言。

基本上,我们进行两次通过:

  1. 找到最大值,并跟踪与最大值进行比较的元素。
  2. 在与最大值进行比较的元素中找到最大值;结果是第二大元素。

enter image description here

在上图中,12是数组中最大的数字,并且在第一遍中与3、1、11和10相比较。在第二遍中,我们在{3,1,11,10}中找到最大的11,这是原始数组中的第二大数字。

时间复杂度

  • 必须查看所有元素,因此,第1遍的n - 1比较。
  • 由于我们每次将问题分为两半,因此最多有log₂n个递归调用,对于每个递归调用,比较序列最多增长一个;因此,比较序列的大小最多为log₂n,因此,第二遍的log₂n - 1比较。
  • 比较总数<= {n - 1 - log₂n - 1 = n - log₂n - 2

    def secondLargest(xs: IndexedSeq[Int]): Int = {
        def max(lo: Int, hi: Int, ys: IndexedSeq[Int]): (Int, IndexedSeq[Int]) = {
          if (lo >= hi) {
            (ys(lo), IndexedSeq.empty[Int])
          } else {
            val mid = lo + (hi - lo) / 2
            val (x, a) = max(lo, mid, ys)
            val (y, b) = max(mid + 1, hi, ys)
    
            if (x > y) {
              (x, a :+ y)
            } else {
              (y, b :+ x)
            }
          }
        }
    
        val (_, comparisons) = max(0, xs.size - 1, xs)
        max(0, comparisons.size - 1, comparisons)._1
    }
    

答案 4 :(得分:0)

I shall give some examples for better understanding. :
example 1 :
>12 56 98 12 76 34 97 23
>>(12 56) (98 12) (76 34) (97 23)
>>> 56 98 76 97 
>>>> (56 98) (76 97)
>>>>> 98 97
>>>>>> 98   

The largest element is 98

Now compare with lost ones of the largest element 98. 97 will be the second largest.

答案 5 :(得分:0)

  

nlogn实施

      public class Test {
           public static void main(String...args){
              int arr[] = new int[]{1,2,2,3,3,4,9,5, 100 , 101, 1, 2, 1000, 102, 2,2,2};
              System.out.println(getMax(arr, 0, 16));
           }

        public static Holder getMax(int[] arr, int start, int end){
           if (start == end)
             return new Holder(arr[start], Integer.MIN_VALUE);
        else {
          int mid = ( start + end ) / 2;
          Holder l = getMax(arr, start, mid);
          Holder r = getMax(arr, mid + 1, end);

          if (l.compareTo(r) > 0 )
            return new Holder(l.high(), r.high() > l.low() ? r.high() : l.low());
          else
            return new Holder(r.high(), l.high() > r.low() ? l.high(): r.low());
        }
      }

    static class Holder implements Comparable<Holder> {
      private int low, high;
      public Holder(int r, int l){low = l; high = r;}

    public String toString(){
      return String.format("Max: %d, SecMax: %d", high, low);
    }

    public int compareTo(Holder data){
      if (high == data.high)
        return 0;

      if (high > data.high)
        return 1;
      else
        return -1;
    }

    public int high(){
      return high;
    }
    public int low(){
      return low;
    }
  }

}

答案 6 :(得分:0)

为什么不对给定的数组[n]使用这种散列算法?它运行c * n,其中c是检查和散列的恒定时间。并且它进行了比较。

    int first = 0;
    int second = 0;
    for(int i = 0; i < n; i++) {
        if(array[i] > first) {
            second = first;
            first = array[i];
        }
    }

或者我只是不明白这个问题......

答案 7 :(得分:0)

在Python2.7中:以下代码适用于O(nlog log n)以进行额外排序。任何优化?

def secondLargest(testList):
    secondList = []
    # Iterate through the list
    while(len(testList) > 1):
        left = testList[0::2]
        right = testList[1::2]

        if (len(testList) % 2 == 1):
            right.append(0)

        myzip = zip(left,right)
        mymax = [ max(list(val)) for val in myzip ]
        myzip.sort()
        secondMax = [x for x in myzip[-1] if x != max(mymax)][0]

        if (secondMax != 0 ):
            secondList.append(secondMax)
        testList = mymax

    return max(secondList)

答案 8 :(得分:0)

使用以下功能

function getSecondLargest(nums) {
var set = new Set(nums)
var sort = [...set].sort((a, b) => a - b)
var length = sort.length
if (length==1) {
    return `Given Array contain only one element :  ${sort[length - 1]}`
}
    return sort[length - 2]
}

答案 9 :(得分:-1)

mongoose.exports

答案 10 :(得分:-1)

我已经为这个问题编写了python代码。并且代码在注释中包含了所有必要的解释。

# idea : each element is compared to other elements during 
# array_max exploration (n-1 comparison)
#  during this exploration, a list is stored as follows:
#     list=[k,value,a,b,c,d....]
# where k is # of elements with which 'value' is compared during the search for array_max.
# and a,b,c,d are the compared elements.
# so to find the second largest element we need to search 
# array_max in the list where 
# value=array_max. and at max k will be log(n). 


def getmax(l,r,a):
    
    if l<r:
        mid=(r+l)//2

       #list of compared_elements with max_value from the left sub- 
       #part
        comparedleft=getmax(l,mid,a)

        #list of compared_elements with max_value from the right
        #sub-part  
        comparedright=getmax(mid+1,r,a) 


        #comparedleft[1]=max_value of the left sub-part to be 
        #compared with other sub part's 
        # max_value(comparedright[1])
        #increment the k value
        #append the new element with which the value has been 
        #compared
        #return the list which contains max_value for this sub-part at 
        #'value'.
        #remember this list contains the elements with which value 
        #has been compared to.
       
        if comparedleft[1]>comparedright[1]: 
            comparedleft[0]+=1               
            comparedleft.append(comparedright[1]) 
            return comparedleft              
        
        else:                               #if max_value is in right sub-part
            comparedright[0]+=1
            comparedright.append(comparedleft[1])
            return comparedright

    #if len(subpart)==1. Generating list to store 
    #compared_elements (with a[l](an element from array))
    else:                  
        compared=[1,int(a[l])]  
        return compared
        
        
def secondmax(a):
    if len(a)==2:       
        if a[0]>a[1]:
            return a[1]
        else:
            return a[0];
        
    list1=getmax(0,len(a)-1,a)       # n-1 comparison
    list2=getmax(2,list1[0],list1)   # log(n)-1 comparison because 
                                                         # list will contain log(n) element 
                                                         # from [2:k]
    return list2[1]                             # return the max_value of 
                                                        # list1[2:k]


list1=input("enter the array = ").split()
if len(list1)==1:
    print("give array with more than 2 elements")
else:
    c=secondmax(list1)
    print(c)