【问题标题】:How to find kth smallest integer in an unsorted array without sorting the array?如何在不排序数组的情况下找到未排序数组中的第 k 个最小整数?
【发布时间】:2011-06-28 00:36:51
【问题描述】:

所以我得到了一个包含 N 个不同整数的(未排序的)数组 A,我正在尝试实现一个分治算法来找到数组中的第 K 个最小元素(K≤N)(即它是如果 K = 1,则整体最小)。该算法返回数组中第 K 个最小元素的值。在一般情况下,我需要它在 O(N) 时间内运行。谁能给我一些提示?

【问题讨论】:

标签: arrays algorithm language-agnostic selection big-o


【解决方案1】:

Sephy,我会非常小心地完成这个过程。在用算法帮助人们时,你总是必须小心,因为,我不能强调这一点,解决算法问题对程序员来说就像举重对职业运动员来说。知道如何让自己进入像电脑一样的思维模式,是几年后你会得到报酬的事情。因此,如果只是为您提供解决方案,您将成为每 6 个月从一个工作跳到另一个工作的人,而不是成为首席开发人员,或者独自与一家成功的公司一起工作的人。

现在这种咆哮已经不碍事了......

传统上,我们认为算法循环遍历数组一次,然后根据第一个结果以不同的方式循环遍历它,然后重复直到满足某个条件,即 O(n^2)。满足这个条件的有选择排序、插入排序和冒泡排序。

但这不是必须的。如果我们可以将数组正确地划分为段并证明这些段的大小,我们可以将其保持在低阶。

而且,对于大多数分而治之的算法,我们可以从中间开始。

Let A be an array of size N with N distinct elements in it.

Let M be the element that resides at A[N/2]

Let A-large be an array of all elements greater than M.
Let A-small be an array of all elements less than M.

我们对 A-small 和 A large 了解多少?它们的大小相同吗?可能,但可能不会。

size(A-small) > k?还是< k

如果size(A-small) == k - 1,那M不是第k小的元素吗?

我们可以做些什么来为 k 创建一个新值并在这里进行一些递归?

我不会为你完成这个,因为应该有很多东西可以咀嚼。这些是你需要问自己的问题。 @templatetypedef 100% 在正确的轨道上,这只是在扩展它。

如果您还有其他问题,请提出,但这里应该有足够的内容让您在不影响脑力锻炼的情况下解决问题。

【讨论】:

  • 感谢@glowcoder 的建议。多亏了@templatetypedef,我在某种程度上走上了正确的道路,但你让我更清楚了。还有,我很熟悉那个咆哮哈哈,本质上是我父亲的国歌。
【解决方案2】:

作为提示,请考虑快速排序分区步骤的工作原理。它将输入拆分,以便枢轴位于其最终位置,最小的元素位于左侧,较大的元素位于右侧。有了这些信息,并且知道您要查找的索引是什么,您能想出一种递归查找第 k 个元素的方法吗?

【讨论】:

  • 我可能会误解,但这似乎不是 O(n)。我的想法很少(很少),看起来好像是 O(n log n)。
  • 我已经尝试过实现它,但我能想出的唯一方法是,如果我先用快速排序对数组进行排序,然后返回第 k 个元素,但我的教授明确表示不要这样做。跨度>
  • @Mark Wilkins:我认为 templatetypedef 暗示了快速选择算法,这是 O(n) 预期的(但 O(n²) 最坏的情况)。
  • @Mark Wilkins 它是 O(n),因为与快速排序相反,您可以在每次迭代后丢弃数组的另一半。因此,您有 n + n/2 + n/4 + n/8 + ...
  • @sephy7324 让我详细说明一下 templatetypedef 的含义:在快速排序算法的一个拆分步骤之后,您知道有多少元素比您的枢轴小,有多少比您的枢轴大。有了这些知识和您的 K,您可以决定继续使用哪一组。这不是排序。
【解决方案3】:

计算数组中每个整数在另一个数组中出现的次数。

【讨论】:

  • 一个好主意,但是是 O(L),其中 L 是最大值。这意味着如果 L > 2*n(您不能保证它不是),那么您将失去 O(n) 平均值。
  • @glowcoder: 或者如果 L = O(n lg lg n),或者其他一些任意小步高于 O(n)。
【解决方案4】:

对于这样的经典问题,维基百科工作得很好…… 见Selection algorithm on wikipedia

【讨论】:

    【解决方案5】:

    尝试搜索选择算法,或者选择排序算法

    【讨论】:

      【解决方案6】:
      import java.util.Scanner;
      
      
      public class JavaApplication1 {
       public static int findpivot(int a,int b,int c){
           //System.out.println("x");
            if(a > b){
              if(c > a){
                  return a;
              }
              else if(c > b){
                  return c;
              }
              else{
                  return b;
              }
          }
          else{
              if(c > b){
                  return b;
              }
              else if(c > a){
                  return c;
              }
              else{
                  return a;
              }
          }
      }
      
      public static void find(int arr[],int l,int r,int target){
          //System.out.println(1);
          if(l >= r){
              return;
          }
          int mid = (l+r)/2;
             // System.out.println(1);
          int pivot = findpivot(arr[mid],arr[l],arr[r]);
          int i = l;
          int j = r;
          while(i<=j){
              while(arr[i] < pivot)i++;
              while(arr[j] > pivot)j--;
              if(i<=j){
                  int temp = arr[i];
                              arr[i] = arr[j];
                              arr[j] = temp;//
                  i++;
                  j--;
              }
      
          }
          if(target <= (i-1)){
              find(arr,0,i-1,target);
          }
          else{
              find(arr,i,r,target);
          }
      }
      
          public static void main(String args[]){
              Scanner sc = new Scanner(System.in);
              int t = sc.nextInt();
              while(t-->0){
                  int n = sc.nextInt();
                  int arr[] = new int[n];
                  for(int i = 0;i<n;i++){
                      arr[i] = sc.nextInt();
                  }
                  int k = sc.nextInt();
                  find(arr,0,n-1,k-1);
                  System.out.println(arr[k-1]);
              }
      
          }
      
      }
      

      时间复杂度几乎是 O(N)。

      【讨论】:

        【解决方案7】:

        这是我的代码。这是一个 O(n) 的解决方案。我在网上没有找到什么好东西,所以我决定在这里发布。希望对您有所帮助。

        def Smallest(arr, k):
            # # The brute force method
            # if(len(arr)<k):
            #    return 0
            # diff = []
            # for i in range(len(arr)):
            #     for j in range(i+1, len(arr)):
            #         diff.append(abs(arr[i]-arr[j]))
            # sortedDiff = sorted(diff)
            # print(diff)
            # print(sortedDiff)
            # return sortedDiff[k-1]
        
            #Efficient method
            if(len(arr)<k):
                    return 0
            # (i, j, minDiff, count) = (0, 1, arr[1]-arr[0], 0)
            (i, j, minDiff) = (0, 1, [])
            while(i < len(arr)):
                if(j>len(arr)-1):
                    i+=1
                    if(i==len(arr)-1):
                        break
                    j=i+1
                else:
                    minDiff.append(abs(arr[i]-arr[j]))
                    j+=1
            # print(minDiff)
            (minElement, count) = (minDiff[0], 0)
            for i in range(len(minDiff)):
                if(count<k):
                    minElement = minDiff[i]
                    count+=1
                    # print(minElement, count)
                    if(count==k):
                        return minElement
                    else:
                        continue
                else:
                    # print("This part is being hit")
                    continue
        
        
        

        【讨论】:

          猜你喜欢
          • 2016-03-20
          • 2019-05-07
          • 2017-03-04
          • 2021-12-16
          • 1970-01-01
          • 1970-01-01
          • 2014-06-07
          相关资源
          最近更新 更多