簡體   English   中英

使用遞歸查找列表中的第二個最小數字

[英]Find the second smallest number in a list using 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]

您可以編寫遞歸函數來獲取3個參數:到目前為止您遇到的第一個和第二個最小值,以及您未檢查過的列表的其余部分。

然后,通過將list參數的第一個元素與兩個最小的參數進行比較,您可以選擇將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)時間。

你可以使用經典的分而治之。 f(x)是一個返回包含列表x最小和次最小元素的元組(a,b)x

基本情況是x具有0或1個元素。 除了基本情況之外,將列表拆分為2,重復以找到每半個中至少兩個元素,然后選擇這4個中的至少2個作為結果:

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]

這里我使用sys.maxsize作為“無限”。

您可以使用標記來跟蹤您是否處於最外層的呼叫中。

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

我可以想到幾種方法。 慢的是找到給定列表的最大值,然后重復列表的其余部分。 當列表長度為2時,不要進行遞歸調用。

更快的是找到最小的元素,重復列表的其余部分,只迭代兩次。 編寫一個例程,以這種方式找到第n個最小元素,然后將其包裝在一個用n = 2調用它的例程中。

這還不夠開始嗎?

一種可能的方法是創建一個帶有3個參數的函數: list ,以及可選的smallest_valuesecond_smallest 在函數pop中 ,第一個元素將其與最小和第二個最小元素進行比較,並在必要時更改值。 然后使用新list smallestsecond_smallest再次調用該函數。 當列表為空並且返回第二個最小值時,遞歸應該終止。

有一些棘手的狀態(當一個/兩個值尚未設置時)。 但我認為這是實施細節,你可以再次詢問編碼是否有任何問題。

我從問題中理解: - 1.解決方案應該是遞歸的2.沒有內部函數類型的黑客3.它應該返回第二小並接受列表作為參數我的代碼來解決這個問題 -

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程序文件的身份運行,則此代碼有效

你可以沿着這些方向做點什么:

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM