Find the second smallest number in a list using recursion

后端 未结 6 1853
故里飘歌
故里飘歌 2021-02-19 18:08

I know there has been a question asked on this topic, but none of the answers have helped me. I don\'t need help with implementing the code, I just need help sorting through the

相关标签:
6条回答
  • 2021-02-19 18:29

    One possible way is to create a function taking 3 parameters: list, and optional smallest_value and second_smallest. In the function pop the first element compare it to the smallest and second smallest and change the values if necessary. Then call the function again with the new list, smallest and second_smallest. The recursion should terminate when the list is empty and return the second smallest.

    There are some tricky states (when one/both of the values are not yet set). But I think that's implementation details and you can ask again if you have any problems coding it.

    0 讨论(0)
  • 2021-02-19 18:33

    You can write your recursive function to take 3 arguments: the first and second smallest values you've encountered so far, and the rest of the list, which you haven't inspected.

    Then, by comparing the first element of the list argument with the two smallest-so-far, you can choose which 2 of the 3 to pass as the arguments to the next recursion.

    You need to wrap this recursive function in a presentation function, which sets up and calls the recursive one, while handling cases like lists that have less than 2 elements.

    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)
    

    This kind of solution isn't particularly Pythonic -- it's more of a functional programming style.

    Finally, you can pass the arguments on the front of the list, and combine the two functions to get the kind of solution you're looking for:

    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)
    

    Note that this function does some redundant work, because it can't know if it's being called first, or if it's calling itself recursively. Also, + creates a new list, so this code will likely take O(n^2) time for a list of size n.

    0 讨论(0)
  • 2021-02-19 18:34

    What I understand from question :- 1. Solution should be recursive 2. No inner function kind of hack 3. It should return second smallest and accept list as parameter My Code to solve this -

    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
    

    Note - This code works if you run as python program file

    0 讨论(0)
  • 2021-02-19 18:35

    You can use a flag to keep track whether you're in the most outer level of the calls.

    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
    
    0 讨论(0)
  • 2021-02-19 18:39

    You can use classical divide and conquer. Let f(x) be a function that returns a tuple (a,b) containing the smallest and next smallest elements in list x.

    The base cases are when x has 0 or 1 elements. Beyond the base case, split the list in 2, recur to find the least two elements of each half, then pick the least 2 of these 4 as the result:

    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]
    

    Here I'm using sys.maxsize as "infinity."

    0 讨论(0)
  • 2021-02-19 18:41

    I can think of several ways. The slow one is to find the largest value of the given list, and then recur on the rest of the list. When the list length is 2, don't make the recursive call.

    A faster one is to find the smallest element, recur on the remainder of the list, iterating only twice. Write a routine to find the nth smallest element this way, and then wrap it in a routine that calls it with n=2.

    Is that enough of a start?

    0 讨论(0)
提交回复
热议问题