【问题标题】:Check if the elements and length of two unsorted lists are equal using recursion使用递归检查两个未排序列表的元素和长度是否相等
【发布时间】:2019-03-23 18:51:36
【问题描述】:

我正在尝试编写一个纯递归函数,如果两个未排序列表的长度相同并且包含相同的元素,它将返回 True。我不允许使用任何迭代,只能使用递归。以下是它应该做什么的示例:

>>> SameStuff(['Hello',1,2,3],[3,2,1,'Hello'])
True
>>> SameStuff(['HELLO',1,2,3],[3,'two',1,'Hello'])
False
>>> SameStuff([1,2],[])
False

我正在为我的递归函数的逻辑而苦苦挣扎,并且缺少一些元素。这是我所拥有的:

def SameStuff(list1,list2):
    if len(list1)!=len(list2):
        return False
    if #some base case:
        #return True?
    if list1[0] in list2:
        return SameStuff(list1[1:],list2)
    else:
        return False

【问题讨论】:

  • 大概基本情况是两个列表都是空的
  • “无序列表”是什么意思?列表本质上是有序的。你的意思是未排序
  • 第一种情况和第三种情况一起表示这行不通。一旦您调用从 one 列表中删除一个元素的函数,它将返回 False。
  • @mkrieger - 是的,递归的情况是错误的。我认为你也不能在 1-liner 中做到这一点。但这就是需要解决的所有问题,除了添加两个列表都为空的基本情况。
  • 要编写递归函数,先从特定情况(空列表、一个元素的列表等)开始,然后是名义情况。

标签: python python-3.x list recursion


【解决方案1】:

我认为您的大部分逻辑都在正确的位置。您只是错过了两者都为空的情况,到那时它们可能是不同(可能)顺序的相同列表!

使用 remove 函数可能效率不高,但从两个不同的无序列表中弹出相同的元素很棘手。

def SameStuff(l1, l2):
    if not l1 and not l2:
        return True

    if len(l1) != len(l2):
        return False

    last_element = l1[-1]
    if last_element not in l2:
        return False

    l1.remove(last_element)
    l2.remove(last_element)

    return SameStuff(l1, l2)

【讨论】:

  • 这也会改变原始列表。如果它们包含相同的东西,我们可能永远不知道它们是否一开始就为空:)
  • 另外,.remove 是隐式迭代。
  • 我不确定列表为空的这一点是否真的对这个用例很重要。 OP 只想知道它们是否具有相同的长度并具有相同的元素。关于删除的观点是公平的。您如何建议在不迭代的情况下删除两个不同列表之间的相同项目?
  • OP 说“长度相同,包含相同的元素”(强调“是”:) 不确定是否需要从列表中删除项目。
【解决方案2】:
def SameStuff(list1, list2):

    # if both empty, they are equal
    if not list1 and not list2:
        return True

    # if unequal lengths, they are not equal
    if len(list1) != len(list2):
        return False

    # grab the first item from list1
    item = list1[0]

    # if it isn't in list2, they are not equal
    if item not in list2:
        return False

    # make copies so we don't disturb the original lists
    newlist1 = list1[:]
    newlist2 = list2[:]

    # remove the item from both copies
    newlist1.remove(item)
    newlist2.remove(item)

    # call ourself with the list copies
    return SameStuff(newlist1, newlist2)

【讨论】:

    【解决方案3】:

    重要的是要说明,如果两个列表都为空,则代码中缺少的基本情况是测试。

    另一个重要因素是避免从两个接收列表中删除找到的元素,因为这可能会在调用后改变它们。

    这与你的代码相同,在我看来修改最少:

    def SameStuff(list1,list2):                                                   
        if len(list1)!=len(list2):
            return False
        if len(list1) == 0 and len(list2) == 0:
            return True
        if list1[0] in list2:
            list2b = list2[:]
            list2b.remove(list1[0])
            return SameStuff(list1[1:], list2b)
        else:
            return False
    
    
    print(SameStuff(['Hello',1,2,3], [3,2,1,'Hello']))
    print(SameStuff(['HELLO',1,2,3],[3,'two',1,'Hello']))
    print(SameStuff([1,2],[]))
    

    【讨论】:

      【解决方案4】:

      为了不产生任何循环,您可以在函数的输入中添加一个参数:

      def SameStuff(list1,list2,i):
          if list1==[] and list2==[]:
              return True
      
          elif i>=len(list1):
              return False
      
          elif len(list1)!=len(list2):
              return False
      
          elif list1[i]==list2[0]:
              del list1[i]
              del list2[0]
              return SameStuff(list1,list2,0)
          else:
              return SameStuff(list1,list2,i+1)
      
      
      print(SameStuff(["hello",1,4],[1,3,"hello"],0))
      print(SameStuff(["hello",1,3],[1,3,"hello"],0))
      

      【讨论】:

        【解决方案5】:
        def SameStuff(l1, l2):
            if l1 == []: return l2 == []    # if recursed down to empty lists -> True
            elif len(l1) != len(l2): return False   # if any length differences -> False
            elif l1[0] in l2: 
                i = l2.index(l1[0]) # identify index of first in l2 identical to l1[0]
                return SameStuff(l1[1:], l2[:i] + l2[i+1:]) # l2 without this element!
            else: return False
        

        这与订单无关。 并且如果某些元素多次出现。

        【讨论】:

        • 当两个列表都包含list1[0] 的多个副本时,我不相信您的else 子句有效。只会从 list1 中删除一个副本,但会从 list2 中删除所有副本。
        • @John Gordon:没错!我必须修复它。谢谢!
        • @John Gordon:现在它也修复了两个列表中的重复元素。
        【解决方案6】:
        def SameStuff(l1, l2):
            if l1 and l2:  # both contain something
                try:
                    index = l2.index(l1[0])
        
                    return SameStuff(l1[1:], l2[:index] + l2[1 + index:])  # recurse
        
                except ValueError:
        
                    return False  # a value in one wasn't found in the other
        
            return not(l1 or l2)  # only one contains something (False), or neither do (True)
        

        【讨论】:

          【解决方案7】:

          另一个想法是再插入三个默认参数(第一个函数调用不需要这些参数):一个空字典、一个整数索引和一个布尔值。

          使用布尔值来指示我们正在遍历哪个列表,并使用索引来指向当前列表元素(我们也可以在索引上使用符号而不是布尔值)。遍历第一个列表时,在字典中记录遇到的每个唯一元素的计数,使用元素作为键。最后,翻转布尔值并遍历第二个列表,这次从字典中的元素计数中减去。删除任何达到零计数的元素。假设我们已经测试了匹配列表长度,如果在字典中找不到元素,则列表不匹配。

          【讨论】:

            猜你喜欢
            • 2021-12-08
            • 2021-07-02
            • 2021-03-10
            • 1970-01-01
            • 2015-12-29
            • 2012-01-10
            • 2012-03-26
            • 2022-12-18
            • 2021-02-13
            相关资源
            最近更新 更多