【问题标题】:How to use recursion to determine if characters are in a string? [closed]如何使用递归来确定字符是否在字符串中? [关闭]
【发布时间】:2014-09-20 07:15:28
【问题描述】:

现在我正在尝试使用具有两个参数的函数的递归来查找第二个参数是否包含在第一个参数中。举个例子:

def recurseString(full, inclusive):
    ...............

有了这个,我会采取以下方式:

recurseString('jack','kcj')

这将返回“True”,而类似:

recurseString('stan','xun')

将返回“假”

我对 python 比较陌生,所以这很令人困惑。关于如何解决这个问题的任何想法?

【问题讨论】:

  • 你为什么要为此使用递归?
  • 另外,您所说的“包含在”到底是什么意思?你的意思是inclusive中的每个字符也在full中,重复的字符必须重复匹配?还是有什么不同?
  • 这是作业题吗?

标签: python string python-2.7 recursion


【解决方案1】:

我猜你正在寻找......

In [51]: def recurseString(a,b):
   ....:     if b == '': return True
   ....:     else:
   ....:         if len(b) == 1: return b in a
   ....:         else: return (b[0] in a) and recurseString(a, b[1:])
   ....:

In [52]: recurseString('jack', 'kjc')
Out[52]: True

In [53]: recurseString('stan', 'xun')
Out[53]: False

但是,不需要递归。使用all 可以更好地解决这个问题,如下所示:

In [57]: all( [s in 'jack'  for s in 'kjc'] )
Out[57]: True

这更像是 Pythonic。

也可以使用reduce,它更具功能,但可读性要差得多,因为 Python 有更好的处理方式。

In [60]: reduce(lambda x,y: (x and (y in 'jack'))  , 'kjc', True)
Out[60]: True

最后,如果不使用 set 符号,这将是不完整的:

In [65]: (set('kjc') - set('jack')) == set()
Out[65]: True

所以如你所见,递归版本最不适合这个问题!

【讨论】:

  • 您可以在对all() 的调用中省略[] 以防止创建额外的列表对象
  • 谢谢杰森。我先试过了。出于某种原因,它创建了一个生成器对象:In [55]: print all( s in 'jack' for s in 'kjc' ) <generator object <genexpr> at 0x085B0F80>。不知道为什么...
  • 这很奇怪。我在 python 2 和 3 中运行它以确保它为我工作(tm)。那应该是没有all() 的输出
  • 你不打印它,它是一个生成器表达式,所以打印它会打印对象。
  • 那是我从 iPython 复制的。不确定这台电脑是否有问题。当我在家用电脑上试用它时,它通常可以工作。这就是我添加print 语句的原因,希望打印会强制生成器评估并打印结果。没用:(。我什至试过` In [54]: all( s in 'jack' for s in 'kjc' ) Out[54]: at 0x05D33350>`
【解决方案2】:

即使inclusive 中有重复的字母,但 full 中只有一个,这将返回 True:

def recurseString(full, inclusive):
    if not inclusive:
        return True
    return inclusive[0] in full and recurseString(full, inclusive[1:])

>>> print recurseString('jack','kkkcccjjj')
True

以下要求full 包含相同数量的重复 字母 - 如果inclusive 有三个 k,full 必须有三个 k:

def recurseString(full, inclusive, first_call = True):
    # first time through, sort the arguments to make the algorithm easier
    if first_call:
        full, inclusive = map(sorted, (full, inclusive))
        first_call = False
    # two base cases, inclusive has been exhausted
    if not inclusive:
        return True
    try:
        index = full.index(inclusive[0])
    except ValueError:
        # and (2nd base case) first item of inclusive is not in full
        return False
    return recurseString(full[index+1:], inclusive[1:], first_call)


>>> print recurseString('jack','kkkcccjjj')
False
>>> print recurseString('jckackjkjc','kkkcccjjj')
True
>>> 

使用index 方法看起来像作弊 -

def foo(full, inclusive, first_call = True):
    if first_call:
        full, inclusive = map(sorted, (full, inclusive))
    if not full and inclusive:
        return False
    if not inclusive:
        return True
    if inclusive[0] == full[0]:
        inclusive = inclusive[1:]
    return foo(full[1:], inclusive, False)


assert not foo('','kkkcccjjj')
assert not  foo('sun','xun')
assert not  foo('jack','kkkcccjjj')
assert foo('s', 's')
assert foo('jckackjkjc','kkkcccjjj')
assert foo('','')
assert foo('a','')

【讨论】:

  • 第一个函数是递归过程。第二个函数是递归过程。
【解决方案3】:

要递归地考虑任何问题,您必须将其分解为一个基本案例(或有时多个基本案例)和一个递归案例(或有时多个递归案例)。

我将假设“被包含”的意思是“inclusive 中的每个字符也在full 中,实际上每个出现在inclusive N 次的字符也至少在full 中N次”。

所以,如果inclusive 是空的,那么它就是空虚的。

但如果full 为空而inclusive 不是,则为False。

否则,如果full 的第一个字符包含在内,则当full[1:] 包含inclusive 减去该字符时,它是真的。

否则,如果full[1:] 包含inclusive,则为真。

现在您只需将其转换为代码。

如果您不需要处理重复的字符,您可以通过仅测试 inclusive[0] 并在 inclusive[1:] 上递归而不是在 full[1:] 上递归来简化此操作。

【讨论】:

  • 反对票有什么解释吗?
【解决方案4】:
def recurseString(str1,str2):
    if str2 == "": #  str2 == "" all str2 letters are in str1
        return True
    elif str2[0] in str1:
        return recurseString(str1, str2[1:]) # move to next letter in str2
    return False # if we get here we have found a letter that is not in str1

In [22]: recurseString('stan','xun')
Out[22]: False

In [23]: recurseString('jack','kcj')
Out[23]: True

【讨论】:

  • 我不确定这是否正确;这取决于recurseString('jack', 'kcjj') 应该是真还是假,OP 没有告诉我们……
  • 另外,str1 == str2 检查也无济于事; 'spam' == 'maps' 不是真的,但无论如何你已经达到“两个字符串相等”。您可以比较 sorted(如果重复计算)或 set(如果不计算重复),但这似乎过于复杂。
  • @abarnert 如果 str1 是垃圾邮件,而 str2 是垃圾邮件,您为什么还要走得更远?我很确定代码是正确的,否则 OP 将需要很长时间才能弄清楚如何递归解决更复杂的版本
  • 如果str1'spam'str2'maps',你为什么还要走得更远?这是一个可能不需要的额外优化,为什么要添加它?
  • @abarnert,很公平,我删除了它,但是两个相同的单词与两个具有相同字母的单词略有不同。
【解决方案5】:

我不知道你为什么需要递归来实现它,它很难阅读和理解。

我的上帝,阅读我的代码对我来说是一个挑战。

def recurseSring(full, inclusive):
    for i in range(len(full)):
        for j in range(len(inclusive)):
            if full[i] == inclusive[j]:
                if recurseSring(full[i + 1:], inclusive[j + 1:]):
                    return True
            if full[i] == inclusive[j] and len(inclusive) == 1:
                return True
    return False


if __name__ == "__main__":
    if recurseSring('lifenglifeng001', 'lifeng'):
        print('OK, equal')
    else:
        print('NOT equal')

【讨论】:

    【解决方案6】:

    短而甜。

    def recurseString(full, incl):
        return incl[:1] in full and (incl[:1] == '' or recurseString(full, incl[1:]))
    

    'and' 确保表达式的两个部分都为真。

    第一部分 - 取 inclusive 的第一个字符并在整个字符串中搜索它:

    incl[:1] in full     #returns '' if incl is ''
    

    第二部分 - 如果您使用空字符串 (incl) 进行搜索,则为 true,如果递归调用为 true,则使用 incl 的尾部作为第二个 arg 调用:

    incl[:1] == '' or recurseString(full, incl[1:])    
    #null check is first to prevent overflow
    

    【讨论】:

      【解决方案7】:

      没有递归有一个简单的方法:用你想要的字符串创建两个集合,然后检查一个集合是否在另一个集合中。

      def contains(text, chars):
          textset = set(text)
          charset = set(chars)
          return charset.issubset(textset)
      
      print contains("jackie", "ice") # True
      print contains('jack','kcj') # True
      print contains('stan','xun') # False
      

      【讨论】:

      • 这不是递归的。这可能是一个毫无意义的问题,但这并不意味着这是该问题的答案。
      • 另外,为什么要set(list(text))?任何可以传递给list 的迭代也可以直接传递给set。 (另外,issubset 可以为其第二个参数采用可迭代对象。)
      • 因为这不是递归算法
      • aaa 你需要为此使用递归算法吗?为这个问题指出另一个解决方案有什么问题吗?我认为这就是 StackOverflow 的想法,让我们分享想法,而不是讨厌:)
      • 你看问题了吗?
      猜你喜欢
      • 2019-08-09
      • 1970-01-01
      • 2018-01-06
      • 1970-01-01
      • 2013-04-13
      • 2014-03-30
      • 1970-01-01
      • 1970-01-01
      • 2014-02-22
      相关资源
      最近更新 更多