If the match is not resolved, this problem becomes much more complicated than it seems at first glance. As far as I can tell, no other answer is correct (see Test Examples at the end).
Recursion is necessary because if a substring appears more than once, using one input instead of another can interfere with other substrings.
This answer uses two functions. The first finds each occurrence of a substring in a string and returns an iterator of strings where the substring has been replaced by a character that should not appear in any substring.
The second function recursively checks if there is a way to find all the numbers in a string:
def find_each_and_replace_by(string, substring, separator='x'): """ list(find_each_and_replace_by('8989', '89', 'x')) # ['x89', '89x'] list(find_each_and_replace_by('9999', '99', 'x')) # ['x99', '9x9', '99x'] list(find_each_and_replace_by('9999', '89', 'x')) # [] """ index = 0 while True: index = string.find(substring, index) if index == -1: return yield string[:index] + separator + string[index + len(substring):] index += 1 def contains_all_without_overlap(string, numbers): """ contains_all_without_overlap("45892190", [89, 90]) # True contains_all_without_overlap("45892190", [89, 90, 4521]) # False """ if len(numbers) == 0: return True substrings = [str(number) for number in numbers] substring = substrings.pop() return any(contains_all_without_overlap(shorter_string, substrings) for shorter_string in find_each_and_replace_by(string, substring, 'x'))
Here are some examples:
tests = [ ("45892190", [89, 90], True), ("8990189290", [89, 90, 8990], True), ("123451234", [1234, 2345], True), ("123451234", [2345, 1234], True), ("123451234", [1234, 2346], False), ("123451234", [2346, 1234], False), ("45892190", [89, 90, 4521], False), ("890", [89, 90], False), ("8989", [89, 90], False), ("8989", [12, 34], False) ] for string, numbers, should in tests: result = contains_all_without_overlap(string, numbers) if result == should: print("Correct answer for %-12r and %-14r (%s)" % (string, numbers, result)) else: print("ERROR : %r and %r should return %r, not %r" % (string, numbers, should, result))
And the corresponding conclusion:
Correct answer for '45892190' and [89, 90] (True) Correct answer for '8990189290' and [89, 90, 8990] (True) Correct answer for '123451234' and [1234, 2345] (True) Correct answer for '123451234' and [2345, 1234] (True) Correct answer for '123451234' and [1234, 2346] (False) Correct answer for '123451234' and [2346, 1234] (False) Correct answer for '45892190' and [89, 90, 4521] (False) Correct answer for '890' and [89, 90] (False) Correct answer for '8989' and [89, 90] (False) Correct answer for '8989' and [12, 34] (False)