如何找到最大集合元素的


14

我有一个算法问题。

ŤñSTaSa|S|

例如:

  1. 如果 = [1、3、4、1、3、6],则可以为[3、3、6]或[3、4、6]或[4、3、6]。TS
  2. 在 = [7,5,1,1,7,4]中,则为[7,5,7,4]。小号TS

我已经尝试过此递归函数。

function(T):
    if minimum(T) >= length(T): 
        return T
    else: 
        return function(T\minimum(T))

是否有任何非递归算法。(我没有检查我的递归算法,所以它可能有一些缺陷。)

Answers:


14

对T排序。然后在 T[i] >= i+1

例如sorted(T)=[6,4,3,3,1,1]。然后,T[0] = 6 > 1T[1] = 4 > 2T[2] = 3 <= 3最后,T[3] = 3 < 4所以我们有S = [T[0], T[1], T[2]]


3
这,当然,忽略了其他的解决办法,但它出现在OP一直在寻找的任何解决方案,而不是所有的解决方案。{633}
瑞克·德克

2
它得到正确的元素数量。我们知道我们有3个元素的解决方案,但没有4个元素。在这种情况下,我们有4个≥3的元素,因此我们知道可以从中选择任意3个作为解决方案。
gnasher729

3
我会很感激正确性。
拉斐尔

我认为您可以使用introselect的变体在O(n)时间内完成此操作。
user2357112支持莫妮卡

8

从我最初的评论:这是密切相关的学术生产力评估数量无处不在,在赫什指数,更好地被称为 -indexh。简而言之,它的定义是出版物的数量,每个出版物至少被h引用(最大的h)。hhh

您的问题与众不同的唯一方法是,您不仅会对满足该标准的出版物数量感兴趣,而且会对它们的引文计数是多少感兴趣,但这是一个微不足道的修改。数据已经存在,原始算法只是将其删除。

通常执行的计算非常简单,并且与KarolisJuodelė的回答一致

更新:根据数据的大小和特征,可能值得探索一些方法,这些方法通过过滤关键点上方和下方的数据对数组进行部分排序(很快就会想到)。然后根据是否太少或太多来调整枢轴并重做包含它的子集,依此类推。您不需要高于元素之间的顺序,当然也不需要那些低于h的元素之间的顺序。因此,举例来说,一旦找到所有大于或等于h 1的元素并且少于h 1,则无需再次触摸该子集,只需对其进行添加即可。这会将快速排序固有的递归转换为尾递归,因此可以将其重写为循环。hh1h1

我的Haskell有点生锈,但这应该可以完成我上面描述的操作,并且似乎可以正常工作。希望可以一​​定程度地理解,我很乐意提供进一步的解释。

-- just a utility function
merge :: [a] -> [a] -> [a]
merge [] ys = ys
merge (x:xs) ys = x : merge xs ys

-- the actual implementation
topImpl :: [Int] -> [Int] -> [Int]
topImpl [] granted = granted
topImpl (x:xs) granted
  | x == (1 + lGreater + lGranted) = x : merge greater granted
  | x > (1 + lGreater + lGranted) = topImpl smaller (x : merge greater granted)
  | otherwise = topImpl greater granted
  where smaller = [y | y <- xs, y < x]
        greater = [y | y <- xs, y >= x]
        lGreater = length greater
        lGranted = length granted

-- starting point is: top of whole array, granted is empty
top :: [Int] -> [Int]
top arr = topImpl arr []

这个想法是收集granted您肯定会参与结果的内容,而不是对其进行进一步排序。如果greater加上x配合,我们很幸运,否则我们需要尝试用一个较小的子集。(枢轴x根本不管碰巧,因此目前考虑的子表的第一个项目。)注意,对一个以最大的元素之一显著的优势是,我们做到这一点的平均大小的块,,无需进一步排序。remaining/2

例:

让我们开始吧[1,3,4,1,3,6]

  1. x = 1granted = []greater = [3,4,1,3,6]。哎呀,当smaller第一步的枢轴太小(实际上太小以至于是空的)时,我们遇到了一个病理案例。幸运的是我们的算法已经为此做好了准备。它会丢弃xgreater单独尝试。

  2. x = 3granted = []greater = [4,3,6]。它们在一起形成一个长度为4的数组,但是我们只能从下面将其限制为3,所以这太多了。greater独自重复一次。

  3. x = 4granted = []greater = [6]。这给出了一个2个元素,每个元素≥4的数组,似乎我们可能会用到更多元素。保持此状态并重复smaller = [3]

  4. x = 3granted = [4,6]greater = []。这一起给出了3个元素,每个元素≥3的数组,因此我们有了解决方案[3,4,6],可以返回。(请注意,置换可根据输入的顺序有所不同,但将始终包含尽可能高的条件,从来没有[3,3,6][3,3,4]为你的榜样。)

(顺便说一句,递归实际上只是崩溃了一个循环。)由于保存了很多比较,因此复杂度比快速排序好一些:

n1

O(logn)O(n)

nO(n2)

上面的代码中有一些不必要的比较,例如计算smaller是否需要我们,可以轻松删除它们。(我认为懒惰的评估会解决这个问题。)


6

您的算法没有错,当然大多数递归算法都可以转换成循环,这里是您的递归代码的循环版本:

function(T):
    while minimum(T) <= lenght(T):
         remove minimum(T) from T
    loop

6
所有递归算法都可以转换为循环。毕竟,图灵机对递归一无所知。
David Richerby '16

4

可以重写任何递归算法以使用迭代。毕竟,图灵机对递归一无所知,但是可以实现任何算法。原则上,您可以通过编写自己的堆栈操作代码来记住函数参数的值以及它可能具有的任何局部变量,从而重写递归函数。在这种情况下,您的函数是尾递归的(一旦返回了递归调用,调用它的函数也立即返回),因此您甚至不需要维护堆栈。


3

使用min-heap进行部分堆排序,因为您不需要对整个数组进行排序。

不断贪婪地弹出元素,直到超过给定的阈值。


2
同样,在这里,我将对正确性的想法表示赞赏。
拉斐尔
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.