【问题标题】:Recursive function to obtain non-repeated characters from string从字符串中获取非重复字符的递归函数
【发布时间】:2021-06-24 18:38:18
【问题描述】:

我有这个练习:

编写一个递归函数,接受一个字符串并返回该字符串中不重复的所有字符。

输出中的字符不需要与输入字符串中的顺序相同。

首先我尝试了这个,但考虑到函数停止的条件,它永远不会计算最后一个字符:

i=0
lst = []

def list_of_letters_rec(str=""):
    if str[i] not in lst and i < len(str) - 1:
        lst.append(str[i])
        list_of_letters_rec(str[i+1:])
    elif str[i] in lst and i < len(str) - 1:
        list_of_letters_rec(str[i+1:])
    elif i > len(str) - 1:
        return lst
    
    return lst

word = input(str("Word?"))

print(list_of_letters_rec(word))

这个函数的主要问题是它从不计算最后一个字符。 输出示例:

['a', 'r', 'd', 'v'] 用于输入“土豚”。

由于不需要对字符进行排序,我想更好的方法是向后递归,我还尝试了另一种方法(如下),但没有运气:

lst = []
def list_of_letters_rec(str=""):
    n = len(str) - 1
    if str[n] not in lst and n >= 0:
        lst.append(str[n])
        list_of_letters_rec(str[:n-1])
    elif str[n] in lst and n >= 0:
        list_of_letters_rec(str[:n-1])
    return lst

word = input(str("Word?"))

print(list_of_letters_rec(word))

显然,停止条件没有很好地定义,尤其是在最后一个,因为我得到的输出是

IndexError: 字符串索引超出范围

您能否给我任何提示以帮助我在第 1st 或 2nd 尝试中更正停止条件?

【问题讨论】:

  • 您的代码引用了未定义的变量lstlista...
  • @trincot 谢谢!我不是以英语为母语的人,因此代码与最初的方式有点“适应”。已经更正了那一点。
  • 您不应为变量赋予与常用内置函数相同的名称,即不应调用您的字符串str
  • 您使用的逻辑存在错误,但您在第二个版本中输入超出范围的原因是因为您在检查n&gt;=0 之前调用了str[n]。如果您只是交换这两个语句,程序将运行(尽管输出仍然不正确)。
  • 为什么在这种情况下引用函数外部的变量,即lst。使函数过于复杂,通常是不好的形式。

标签: python string list recursion


【解决方案1】:

你可以试试:

word = input("> ")
result = [l for l in word if word.count(l) < 2]

>  aabc
['b', 'c']

Demo

【讨论】:

  • 注意OP约束:“有一个练习需要我做一个递归函数
  • 这只是一个例子,OP可以将其转换为递归函数。
  • @PedroLobito——我没有投反对票。我认为您的回答是非递归解决方案的一个很好的例子。
  • @PedroLobito 非常感谢您的回答!即使不是递归的,它也是解决问题的一种非常简单的方法,它肯定会对我有所帮助。顺便说一句,我也没有投反对票(甚至没有足够的代表能够做到这一点)。
【解决方案2】:

一些问题:

  • 由于条件句中的i &lt; len(str) - 1,您错过了最后一个字符。那应该是i &lt; len(str)(但请阅读下一点,因为这仍然需要更改)
  • 应首先测试if i &gt; len(str) - 1,然后再执行其他任何操作,否则您将获得无效的索引引用。这也使得关于长度的其他条件变得不必要了。
  • 不要将变量命名为 str,因为这已经是字符串类型的使用名称。
  • 不要填充全局列表。通过这样做,您只能可靠地调用该函数一次。下次列表仍将具有上一次调用的结果,您将添加到该列表中。而是使用从递归调用中获得的列表。在基本情况下,返回一个空列表。
  • 全局i 没有用,因为你永远不会改变它的值;它总是 0。所以你应该只引用索引[0] 并检查字符串是否为空。

这是您的代码,其中包含这些更正:

def list_of_letters_rec(s=""):
    if not s:
        return []
    result = list_of_letters_rec(s[1:])
    if s[0] not in result:
        result.append(s[0])
    return result

print(list_of_letters_rec("aardvark"))

注意:这不是最好的方法。但我想这是你被要求做的。

【讨论】:

  • 很好的答案和建议。
  • @trincot 非常感谢! :) 我特别感谢有关正确定义停止条件和变量的建议。我最终设法使我的代码工作但使用嵌套的 ifs,所以你的代码更简单/更好。
【解决方案3】:

一个可能的解决方案是只使用索引而不是拼接字符串:

def list_of_letters_rec(string="", index = 0, lst = []):
    if(len(string) == index):
        return lst
    char = string[index]
    if  string.count(char) == 1:
        lst.append(char)
    return list_of_letters_rec(string, index+1, lst)
word = input(str("Word?"))
print(list_of_letters_rec(word))

【讨论】:

  • 感谢您的回答!我认为这个练习意味着只有一个输入,即字符串,但看到另一种方法真的很有趣,而且它也有助于学到更多东西! :)
【解决方案4】:

我对@trincot 的回答的一个改进是使用set,与列表相比,它具有更好的查找时间O(1)O( n).

  1. 如果输入字符串s为空,则返回空结果
  2. (归纳)s 至少有一个字符。如果第一个字符 s[0] 在备忘录中,mem,则该字符已被看到。返回子问题的结果,s[1:]
  3. (归纳)备忘录中的第一个字符是not。将第一个字符添加到备忘录中,并将第一个字符添加到子问题的结果s[1:]
def list_of_letters(s, mem = set()):
  if not s:
    return ""                                           #1
  elif s[0] in mem:
    return list_of_letters(s[1:], mem)                  #2
  else:
    return s[0] + list_of_letters(s[1:], {*mem, s[0]})  #3

print(list_of_letters("aardvark"))
ardvk

根据您的评论,该练习仅要求输入字符串。我们可以很容易地修改我们的程序来私有化mem -

def list_of_letters(s):                         # public api
  def loop(s, mem):                             # private api
    if not s:
      return ""
    elif s[0] in mem:
      return loop(s[1:], mem)
    else:
      return s[0] + loop(s[1:], {*mem, s[0]})
  return loop(s, set())                         # run private func

print(list_of_letters("aardvark"))              # mem is invisible to caller
ardvk

Python 的原生 set 数据类型接受可立即解决此问题的可迭代对象。然而,这并没有教你任何关于递归的知识:D

print("".join(set("aardvark")))
akdrv

【讨论】:

  • 虽然我认为最初的练习要求只使用一个字符串变量作为输入/输出,但这是一个非常受欢迎的输入/改进建议。也解释的很清楚。非常感谢,@谢谢!!
  • 我很乐意提供帮助。我进行了编辑,显示了如何使 mem 对调用者不可见
猜你喜欢
  • 2021-09-22
  • 2018-03-04
  • 2020-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多