Palindrome check with recursive function without slicing and loops - python

I have an assignment, I have to make a python code that checks whether a string is a palindrome using a recursive function that returns a boolean, but I am not allowed to use reversed slicing nor loops, and I am not allowed to change the function format, here's my code but it returns True all the time
def is_palindrome(s):
res = []
s = ['']
if len(s) < 2:
return True
else:
rev_s = is_palindrome(s[1:]) + s[0]
res.append(rev_s)
if res == s:
return True
return False

You can check if the first and the last character of the given string are the same and then recursively check if the remaining string is a palindrome instead:
def is_palindrome(s):
return len(s) < 2 or s[0] == s[-1] and is_palindrome(s[1:-1])

I'm not sure if this counts as 'changing the function format', but here's my stab at a recursive version without slices:
def is_palindrome(s):
def is_palindrome_r(i, j):
if j <= i:
return True
if s[i] != s[j]:
return False
return is_palindrome_r(i + 1, j - 1)
return is_palindrome_r(0, len(s) - 1)
The inner function, is_palindrome_r, is the recursive function that takes two indexes, i and j. The last line sets the initial positions for these two indexes at 0 (the start of the string) and len(s) - 1 (the end of the string) and proceeds with the recursive logic. The recursive function has two exit conditions:
if j <= i we've reached the center of our palindrome. If we've gotten this far, we know all the other pairs of characters match and we don't need to do any more comparisons.
if the two characters pointed to by i and j do not match, it's definitely not a palindrome and we don't need to do any more comparisons.
Otherwise we don't yet know if the sequence is fully palindromic, so we we move our indexes one step inward (i + 1, j - 1) and go back to step 1.

No slicing used, just maintain the indices through the recursive calls
def is_palindrome(s):
return helper(s, 0, len(s)-1)
def helper(s, i, j):
if (i >= j):
return True
return s[i] == s[j] and helper(s, i+1, j-1)

If the mentioned function signature def is_palindrome(s) is the signature given by your teacher then no issue and there is no need to pass any extra parameter to achieve the goal.
Your teacher (or the one gave you this task is awesome) just wanted t check how do you handle this with only 1 parameter.
The concept is very simple, just change the type of argument (to list with 3 values) in second recursive call.
def is_palindrome(s):
if type(s) is str:
l = len(s)
if l == 0 or l == 1:
return True
else:
return is_palindrome([s, 0, -1])
else:
string, start, end = s # s is list here
if string[start] != string[end]:
return False
else:
if(start + 1 >= end - 1):
return True
return is_palindrome([s, start + 1, end - 1])
def main():
string1 = "abcba"
string2 = "abcde"
string3 = "AxxA"
print(is_palindrome(string1)) # True
print(is_palindrome(string2)) # False
print(is_palindrome(string3)) # True
main();
The following is not what you're looking for but may be you'll be looking for that in future.
>>> def is_palindrome(s):
... if s == "".join(reversed(s)):
... return True
... else:
... return False
...
>>> is_palindrome("ABA")
True
>>>
>>> is_palindrome("ABC")
False
>>>
>>> is_palindrome("XXZZXX")
True
>>>
>>> is_palindrome("##7")
False
>>>
>>> is_palindrome("1###1")
True
>>>
Thank you.

Related

how to check if a list is a consecutive number in python?

How to write python code that let the computer know if the list is a right sequence and the position doesn't matter, it will return true, otherwise it return false.
below are some of my example, I really don't know how to start
b=[1,2,3,4,5] #return true
b=[1,2,2,1,3] # return false
b=[2,3,1,5,4] #return true
b=[2,4,6,4,3] # return false
sort function is O(nlogn), we can use for loop which is O(n):
def check_seq(in_list):
now_ele = set()
min_ele = max_ele = in_list[0]
for i in in_list:
if i in now_ele:
return False
min_ele = min(i, min_ele)
max_ele = max(i, max_ele)
now_ele.add(i)
if max_ele-min_ele+1 == len(in_list):
return True
return False
Create a set and one to compare with -- based on minimum and maximum:
isRightSequence = set(range(min(b), max(b)+1)) == set(b)
This question is quite simple and can be solved a few ways.
The conditional approach - if there is a number that is bigger than the length of the list, it automatically cannot be a sequence because there can only be numbers from 1-n where n is the size of the list. Also, you have to check if there are any duplicates in the list as this cannot be possible either. If none of these conditions occur, it should return true
Using dictionary - go through the entire list and add it as a key to a dictionary. Afterwards, simply loop through numbers 1-n where n is the length of the list and check if they are keys in the dictionary, if one of them isn't, return false. If all of them are, return true.
Both of these are quite simply approaches and you should be able to implement them yourselves. However, this is one implementation for both.
1.
def solve(list1):
seen = {}
for i in list1:
if i > len(list1):
return False
if i in seen:
return False
seen[i] = True
return False
def solve(list1):
seen = {}
for i in list1:
seen[i] = True
for i in range (1, len(list1)+1):
if i not in seen:
return False
return True
This solution needs O(n) runtime and O(n) space
def is_consecutive(l: list[int]):
if not l:
return False
low = min(l)
high = max(l)
# Bounds Check
if high - low != len(l) - 1:
return False
# Test all indices exist
test_vec = [False] * len(l) # O(n)
for i in range(len(l)):
test_vec[l[i] - low] = True
return all(test_vec)
assert is_consecutive(range(10))
assert is_consecutive([-1, 1,0])
assert not is_consecutive([1,1])
assert not is_consecutive([1,2,4,6,5])

Checking interweaving strings in pythonic way

I have a problem for checking the interweaving strings. So, I have 3 strings and I need to check whether the third string can be formed by interweaving the first two strings.
To simplify, interweaving strings means to merge them by alternating their letters without any specific pattern.
For example: "abc" and "123" are two strings and possible interweaving can be "abc123" or "a1b2c3" or "ab1c23" etc mixing them without any pattern but following order sequence.
another example, for false case:
str1 = "aabcc",
str2 = "dbbca",
str3 = "aadbbbaccc" # This is false case, where str3 is not interweaving from str1 and str2
what i have tried:
I have tried below solution which is working for me. returning True if string c is interweaving of string a and b else returning False
def weavingstring(a,b,c):
for i in c:
if len(a)>0:
if i == a[0]:
a=a[1:]
if len(b)>0:
if i == b[0]:
b=b[1:]
if len(a) > 0 or len(b) > 0:
return False
return True
print(weavingstring("abc", "def", "abcdef")) # True here
print(weavingstring("aabcc", "dbbca", "aadbbbaccc")) # False here
What i want
I have the normal solution, I wanted to know if there is any pythonic way of doing this by using list comprehension, map, filter, reduce or lambda functions etc.
One approach of using the lru_cache with lambda to speed things up:
from functools import lru_cache
class Solution:
def isInterleave(self, s1: str, s2: str, s3: str) -> bool:
return (memo:=lru_cache()
( lambda i=0, j=0, k=0:
(i, j, k) == (len(s1), len(s2), len(s3))
or ( i < len(s1) and k < len(s3) and s1[i] == s3[k] and memo( i+1, j, k+1 ) )
or ( j < len(s2) and k < len(s3) and s2[j] == s3[k] and memo( i, j+1, k+1 ) ) )
)()
May I interest you in a simple recursive solution?
def weaving(a: str, b: str, res: str) -> bool:
if not a: return b == res
if not b: return a == res
if not res: return False
if res[0] == a[0]:
return weaving(a[1:], b, res[1:])
elif res[0] == b[0]:
return weaving(a, b[1:], res[1:])
else:
return False
A simple solution would be to use regexes.
import re
def iswoven(first, second, test):
return all((re.search(r'.*'.join(x), test) for x in (first, second)))
>>> iswoven('abc', '123', 'a1b2c23')
True
>>> iswoven('abc', '123', 'a1b223')
False
This will check that the test string matches both 'a.*b.*c' and '1.*2.*3' and return the result.
Depending on the length of your strings, this could end up trying to match on some pretty hairy regexes, so buyer beware.

How to write this iterative function to be recursive?

I need to write this iterative function to do the same thing but it must be recursive.
def task1(string: str):
for i in range(len(string)):
if string[i] != string[len(string) - i - 1]:
return False
return True
This is what i tried but it does not work.
def task1_recursion(string: str):
print(string)
if len(string) > 1:
if string[0] == task1_recursion(string[1::1]):
return True
else:
return False
else:
return string
My code seems to one the last recursion return string "" and that makes it to return False.
Just check the tip and the tail, continue with the string without them:
def task1_recursion(string: str):
# recursion base condition (exit condition)
if len(string) <= 1:
return True
# unpack values
first, *_, last = string
# check if they are different
if first != last:
return False
# if not continue checking the remaining string
return task1_recursion(string[1:-1])
If I understand correctly you want to check if a string is symmetric with the code in task1. My solution is below:
def fct(s: str, i: int):
if len(s) <= 1 or i == len(s):
return True
return s[i] == s[len(s) - 1 - i] and fct(s, i + 1)
I tested and fct produces the same result as task1. It needs an additional parameter for the index though. But you can wrap it inside another function if you want the parameter to include only the input string. i is always set to 0 when you call the function, e.g. fct("ABCCBA", 0).

Python Recursively check for repeats

I have an assignment I've been stuck on for a couple days now. I have to recursively figure out if a list has repeats but I cannot use any loops or built in functions besides len(). I'm also not allowed to use the 'in' function. Returns True if list L has repeats, False otherwise. This is what I've been able to figure out:
def has_repeats(L):
if len(L) <= 1:
return False
elif L[0] == L[1]:
return True
else: return has_repeats(L[0] + L[2:])
But the problem with that is it's only comparing the first element to the rest, instead of each element to the rest. I can't figure out how to do that without a running counter or something. Any suggestions?
You almost have it. Along with checking the first element with the rest of the list, you also need to check the second the same way:
def has_repeats(L):
if len(L) <= 1:
return False
if L[0] == L[1]:
return True
if has_repeats([L[0]] + L[2:]):
return True
if has_repeats(L[1:]):
return True
return False
You can also compact this into the following representation:
def has_repeats(L):
return len(L)>1 and L[0]==L[1] or has_repeats([L[0]]+L[2:]) or has_repeats(L[1:])
Use a helper function:
def helper(ele, rest):
if not rest:
return False
return ele == rest[0] or helper(ele, l[1:])
def has_repeats(l):
if not l:
return False
return helper(l[0], l[1:]) or has_repeats(l[1:])

How can I return false if more than one number while ignoring "0"'s?

This is a function in a greater a program that solves a sudoku puzzle. At this point, I would like the function to return false if there is more then 1 occurrence of a number unless the number is zero. What do am I missing to achieve this?
L is a list of numbers
l =[1,0,0,2,3,0,0,8,0]
def alldifferent1D(l):
for i in range(len(l)):
if l.count(l[i])>1 and l[i] != 0: #does this do it?
return False
return True
Assuming the list is length 9, you can ignore the inefficiency of using count here (Using a helper datastructure - Counter etc probably takes longer than running .count() a few times). You can write the expression to say they are all different more naturally as:
def alldifferent1D(L):
return all(L.count(x) <= 1 for x in L if x != 0)
This also saves calling count() for all the 0's
>>> from collections import counter
>>> def all_different(xs):
... return len(set(Counter(filter(None, xs)).values()) - set([1])) == 0
Tests:
>>> all_different([])
True
>>> all_different([0,0,0])
True
>>> all_different([0,0,1,2,3])
True
>>> all_different([1])
True
>>> all_different([1,2])
True
>>> all_different([0,2,0,1,2,3])
False
>>> all_different([2,2])
False
>>> all_different([1,2,3,2,2,3])
False
So we can break this down into two problems:
Getting rid of the zeros, since we don't care about them.
Checking if there are any duplicate numbers.
Striping the zeros is easy enough:
filter(lambda a: a != 0, x)
And we can check for differences in a set (which has only one of each element) and a list
if len(x) == len(set(x)):
return True
return False
Making these into functions we have:
def remove_zeros(x):
return filter(lambda a: a != 0, x)
def duplicates(x):
if len(x) == len(set(x)):
return True
return False
def alldifferent1D(x):
return duplicates(remove_zeros(x))
One way to avoid searching for every entry in every position is to:
flags = (len(l)+1)*[False];
for cell in l:
if cell>0:
if flags[cell]:
return False
flags[cell] = True
return True
The flags list has a True at index k if the value k has been seen before in the list.
I'm sure you could speed this up with list comprehension and an all() or any() test, but this worked well enough for me.
PS: The first intro didn't survive my edit, but this is from a Sudoku solver I wrote years ago. (Python 2.4 or 2.5 iirc)

Categories