I'm trying to get the length of the longest substring of message that begins and ends with the string subString
This is the table with what the results should look like: Table with examples and outputs
This is the code I got so far:
dist = 0
def strDist(message, subString):
global dist
if message.find(subString) == -1:
return dist
else:
dist = message.find(subString) len(subString)
return strDist(dist*' ' message[dist:], subString)
and this is the Tester code:
from recursion import *
allPassed = True
def strDistMain():
global allPassed
testCases = [(1, 'cat dog cat dog cat', 'cat', 19),
(2, 'cat dog cat dog ca', 'cat', 11),
(3, 'at dog cat dog cat', 'cat', 11),
(4, 'dog cat dog', 'cat', 3),
(5, 'dog dog', 'cat', 0),
(6, 'cat', 'cat', 3),
(7, 'ca', 'cat', 0),
(8, 'c', 'cat', 0),
(9, '', 'cat', 0),
(10, 'cat', '', 3),
(11, '', '', 0)
]
for num, message, mark, expected in testCases:
result = strDist(message, mark)
if result != expected:
print(f'String Distance Test {num} Failed. Expected {expected} got {result}')
allPassed = False
def main():
strDistMain()
if allPassed:
print('All tests passed')
main()
The code doesn't work at all and I'm not sure what's the problem. This is the output I'm getting so far:
String Distance Test 1 Failed. Expected 19 got 33
String Distance Test 2 Failed. Expected 11 got 36
String Distance Test 3 Failed. Expected 11 got 46
String Distance Test 4 Failed. Expected 3 got 53
String Distance Test 5 Failed. Expected 0 got 53
String Distance Test 6 Failed. Expected 3 got 56
String Distance Test 7 Failed. Expected 0 got 56
String Distance Test 8 Failed. Expected 0 got 56
String Distance Test 9 Failed. Expected 0 got 56
builtins.RecursionError: maximum recursion depth exceeded while calling a Python object
CodePudding user response:
It's not obvious that your strDist
function ever converges toward a base case. Using global
in a recursive function almost always makes it harder to debug and reason about; odds are good that dist
is winding up with a value you don't expect at some point, and that's what's leading to infinite recursion.
Using find
(which is an iterative function) in your recursive function sort of defeats the purpose anyway, since as pointed out, if you're going to use find
to find the leftmost occurrence, you could just also use rfind
to find the rightmost occurence, and then you're done without having to do any recursion at all.
A purely recursive (also inefficient) solution would look more like:
def str_dist(message, substr):
if len(message) < len(substr):
return -1
if message.startswith(substr) and message.endswith(substr):
return len(message)
return max(str_dist(message[1:], substr), str_dist(message[:-1], substr))
The above function is purely recursive in that it doesn't do any iteration over message
within a given function call (note that startswith
and endswith
are both iterative over substr
; you could write recursive versions of those as well if you really wanted to) and it passes all of your tests.
It has two base cases:
- There's no valid answer if
message
is shorter thansubstr
. (Some form of "too small" base case is needed to prevent infinite recursion on empty strings -- you could make the empty string the base case if you wanted to make this check simpler.) - The answer is
len(message)
ifmessage
itself meets the condition of starting and ending withsubstr
.
Otherwise, it's the best answer from either message[1:]
or message[:-1]
.
CodePudding user response:
First of all, you don't need to use recursion, you can just do:
def strDist(message, mark):
if message.find(mark) == -1:
return 0
return message.rfind(mark) - message.find(mark) len(mark)
But, if you want to do it with recursion for some reason, you can just do:
def strDist(message, mark):
index = message.find(mark)
if index == -1:
return 0
return recursive_last(message, mark) - index len(mark)
def recursive_last(message, mark):
index = message.find(mark)
if index == -1:
return -1
return max(index, recursive_last(message[index len(mark):], mark) index)
The first function gets the index of the first occurency, and calls the recursive, that finds the first ocurrency, removes it from the string, and try again.
CodePudding user response:
def f(message,mark,i=0):
if message.count(mark) == 1:
return len(mark)
elif not message.count(mark):
return 0
j = message.find(mark,i)
if j<0:
return i len(mark)-1
elif not i:
message = message[j:]
j = 1
return f(message,mark,i=j 1)
print(f('cat dog cat dog cat dog','cat'))
print(f('cat dog cat dog ca','cat'))
print(f('at dog cat dog cat','cat'))
print(f('dog cat dog','cat'))
print(f('dog dog','cat'))
print(f('ca','cat'))
print(f('cat',''))