使用递归查找列表中的第二个最小数字

时间:2016-02-09 00:43:26

标签: python algorithm recursion

我知道有关于这个主题的问题,但没有一个答案对我有帮助。我不需要帮助实现代码,我只需要帮助对递归过程进行排序。

我最初想的是递归地返回每个级别的元组并进行比较以找到第二个最小值。但这不起作用,因为我希望我的函数最终只返回1个值 - 第二个最小值。

我如何处理此问题的递归过程?谢谢!

编辑:很抱歉没有提供足够的详细信息,所以请点击此处。

功能应如下工作:

>>> sm([1,3,2,1,3,2])
>>> 2

第二次修改 对不起,我很忙,直到现在,终于能够坐下来把我的想法放到代码中了。它按预期工作,但老实说,我认为这是一种非常糟糕和低效的递归方式,因为你可能会说我是新概念。

使用下面的伪代码重新解释我的原始问题:是否可以执行我在此处所做的操作,但不将其包装在第二个函数中?也就是说,是否有可能只有递归调用自身的函数,并返回1个数字 - 第二个最小的数字?

def second_smallest(list):
    def sm(list):
        if base case(len of list == 2):
            return ordered list [2nd smallest, smallest]
        else:
            *recursive call here*
            compare list[0] with returned ordered list
            eg: [3, [5,2]]
            re-arrange, and return a new ordered list
            [3,2]
    return sm(list)[0]

7 个答案:

答案 0 :(得分:3)

您可以编写递归函数来获取3个参数:到目前为止您遇到的第一个和第二个最小值,以及未检查过的列表的其余部分。

然后,通过将list参数的第一个元素与两个最小的-e-far进行比较,您可以选择将3中的哪两个作为参数传递给下一个递归。

你需要将这个递归函数包装在一个表示函数中,该函数设置并调用递归函数,同时处理像少于2个元素的列表这样的情况。

def recurse(min1, min2, list):
    if len(list)==0:
        return min2
    first, rest = list[0], list[1:]
    if first < min1:
        return recurse(first, min1, rest)
    if first < min2:
        return recurse(min1, first, rest)
    return recurse(min1, min2, rest)

def second_smallest(list):
    if len(list) < 2:
        raise ValueError("too few elements to find second_smallest")
    a, b, rest = list[0], list[1], list[2:]
    if b < a:
        return recurse(b, a, rest)
    else:
        return recurse(a, b, rest)

这种解决方案并不是特别的Pythonic - 它更像是一种函数式编程风格。

最后,你可以传递列表前面的参数,并结合这两个函数来获得你正在寻找的那种解决方案:

def second_smallest(list):
    if len(list) < 2:
        raise ValueError("too few elements to find second_smallest")
    a, b = list[0], list[1]
    a, b = min(a,b), max(a,b)
    if len(list) == 2:
        return b
    c, rest = list[2], list[3:]
    if c < a:
        return second_smallest([c,a]+rest)
    if c < b:
        return second_smallest([a,c]+rest)
    return second_smallest([a,b]+rest)

请注意,此函数会执行一些冗余工作,因为它无法知道它是首先被调用,还是它是以递归方式调用自身。此外,+会创建一个新列表,因此对于大小为n的列表,此代码可能需要O(n ^ 2)时间。

答案 1 :(得分:2)

你可以使用经典的分而治之。设describe "POST #create" do it "creates a career" do expect { post "/careers/", career: attributes_for(:career) }.to change(Career, :count).by 1 end end 为一个函数,返回包含列表f(x)中最小和次最小元素的元组(a,b)

基本情况是x有0或1个元素。除了基本情况之外,将列表拆分为2,重复以找到每一半的至少两个元素,然后选择这4个中的至少2个作为结果:

x

我在这里使用def min2(x): if len(x) == 0: return sys.maxsize, sys.maxsize if len(x) == 1: return x[0], sys.maxsize m = int(len(x)/2) a1, b1 = min2(x[:m]) a2, b2 = min2(x[m:]) return (a1, min(b1, a2, b2)) if a1 < a2 else (a2, min(b2, a1, b1)) def secondSmallest(x) return min2(x)[1] 作为“无限。”

答案 2 :(得分:2)

您可以使用标记来跟踪您是否处于最外层的通话中。

def second_smallest(numbers, top_level=True):
    # Do your stuff and call `second_smallest(numbers[1:], False)` for any recursions.
    # When it comes to returning a value from the function, use the following.

    if top_level:
        return result[0]   # what your function ultimately returns
    return result          # [second, first] since you're still in recursive calls

答案 3 :(得分:1)

我可以想到几种方法。慢的是找到给定列表的最大值,然后重复列表的其余部分。当列表长度为2时,不要进行递归调用。

更快的一个是找到最小的元素,重复列表的其余部分,只迭代两次。编写一个例程,以这种方式找到 n 最小元素,然后将其包装在一个用n = 2调用它的例程中。

这还不够开始吗?

答案 4 :(得分:1)

一种可能的方法是创建一个带有3个参数的函数:list,以及可选的smallest_valuesecond_smallest。在函数pop中,第一个元素将其与最小值和第二个最小值进行比较,并在必要时更改值。然后使用新的listsmallestsecond_smallest再次调用该函数。当列表为空并且返回第二个最小值时,递归应该终止。

有一些棘手的状态(当一个/两个值尚未设置时)。但我认为这个实现细节,你可以再次询问编码是否有任何问题。

答案 5 :(得分:1)

我从问题中理解: - 1.解决方案应该是递归的 没有内在功能的黑客攻击 它应该返回第二个最小值并接受列表作为参数 我的代码来解决这个问题 -

from inspect import getouterframes, currentframe
def second_smallest(ls):
    level = len(getouterframes(currentframe(1)))

    if len(ls)<2:
        return None
    if len(ls) == 2:
                if level == 1:
                    return max(ls)
                else:
                    return min(ls), max(ls)
    else:
        m,n = second_smallest(ls[1:])
        if ls[0]<=m:
            n = m
            m = ls[0]
        elif ls[0] < n:
            n = ls[0]
        if level == 1:
            return n
        return m,n

注意 - 如果您以python程序文件

运行,此代码有效

答案 6 :(得分:0)

你可以按照以下方式做点什么:

def rmin(li, n=2):
    def _rmin(li):
        if len(li) == 1:
            return li[0]
        else:
            m = _rmin(li[1:])
            return m if m < li[0] else li[0]  

    a=[]        
    for i in range(n):
        x=_rmin([e for e in set(li) if e not in a]) 
        a.append(x)
    return x