分而治之——未排序数组的k个元素

Posted

技术标签:

【中文标题】分而治之——未排序数组的k个元素【英文标题】:Divide and conquer - k element of unsorted array 【发布时间】:2016-02-05 10:57:41 【问题描述】:

我在尝试使用分而治之的算法时遇到问题。

给定一个未排序的数组 T v[] 查找该数组的 v[k] 元素,就好像该数组已排序但未对数组进行排序 v .

例如,如果 k = 3v = 2, -1, -6, 7, 4 该数组的第 k 个元素是 2

由于我无法编辑传递的数组,我想不出另一种方法来对数组进行排序,而不将其保存在另一个局部变量中或尝试像快速排序一样划分数组并返回 的最后一个元素的位置v 应该是。

如果有帮助,这是我的代码:

public static <T extends Comparable<? super T>> T kesimoRec(T v[], int izq, int der, int k) 
    if(izq < der)
    int inf = izq-1;
    T pivote = v[der];
       for(int i = izq; i < der; ++i)
           if(pivote.compareTo(v[i]) >= 0)
               ++inf;
           
       
       ++inf;
       if(inf > izq + k-1)
           return (kesimoRec(v, izq, inf-1, k));
       else if( inf < izq + k-1)
           return (kesimoRec(v, inf+1, der, k-inf+izq-1));
       else
           return v[inf];
       
    else
        return v[der];
    

【问题讨论】:

这不是quickselect吗? @MikeSamuel - 我的印象是大多数快速选择的实现都进行了部分排序。 @rcgldr,是的,我认为输入已修改到位。如果数组不是共享的 btw 线程,您可能会调整 quickselect 以在找到元素保持不变后交换回来。 @MikeSamuel - 大多数快速选择算法需要对数据进行部分排序以找到第 k 个索引,这就是快速选择的分区阶段所做的。如果不修改原始数据,则可以使用原始数组的副本。 【参考方案1】:

你为什么使用分而治之?

我建议您使用 PriorityQueue。您可以在 Google 上搜索有关 PriorityQueue 的更多信息。一旦你了解了它的工作原理,你会发现很容易想出一个解决方案。我的java代码:

public class Solution 
    public int findKthLargest(int[] nums, int k) 
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>(nums.length);

        for (int num : nums) 
            queue.offer(num);
        

        for (int i = 0; i < nums.length - k; i++) 
            queue.poll();
        

        return queue.peek();
    

嗯,对不起,我的解决方案是找到第 k 个最大的,但是您可以修改它以找到第 k 个最小的。

【讨论】:

我需要使用分而治之,因为这是一个分而治之的练习,我知道有很多方法可以做到,但谢谢你的建议。 @DaryEiki 检查此链接以获取分而治之的解决方案:leetcode.com/discuss/63971/… @DaryEiki 请注意,上面链接中的解决方案也是找到第 k 个最大的。 @EalonWang - 请注意,快速选择/快速排序方法对数组进行部分排序,将小于某个枢轴的值移动到数组左侧,将大于或等于枢轴的值移动到右侧大批。通常当找到第k个元素时,那么所有小于第k个元素的元素都会被移动到元素0到k-1,但不相互排序。【参考方案2】:

分而治之

public static <T extends Comparable<? super T>> T kesimoRec(T v[], int izq,
            int der, int k) 
        if (izq == der) 
            return v[izq];
        
        int pivote = partir(v, v[der], izq, der);
        if (k == pivote) 
            return v[k];
         else if (k < pivote) 
            return kesimoRec(v, izq, pivote - 1, k);
         else 
            return kesimoRec(v, pivote + 1, der, k);
        
    

【讨论】:

以上是关于分而治之——未排序数组的k个元素的主要内容,如果未能解决你的问题,请参考以下文章

分治策略合并多个排序数组

从两个排序数组中获取前 K 项而不合并它们

c_cpp 使用分而治之的方法查找未排序数组中的最小值和最大值

给定已排序的数组,如果数组 A 包含元素 A[i] 使得 A[i] = i (递归和分而治之),则返回索引 i

使用分治算法在未排序的数组中查找最大和

深入浅出:快速排序