Writing a string backwards - python

This is my simple code.
def reverseString(aStr):
newStr = ''
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[len(aStr)-1]
return reverseString(aStr[:len(aStr)-1])
For 'alina' (if I insert print newStr before return reverseString...), the output is: newStr='a', newStr='n', newStr='i', newStr='l', newStr='a', newStr=''. I don't get it. Why does it behave like this?

The reason your function has not worked is because you forgot to return newStr at the end. And every time you call your function, newStr will just get reset back to ''.
There's an easier way to do what you are doing. Use slicing:
def reverseString(s):
return s[::-1]
Examples:
>>> reverseString('alina')
'anila'
>>> reverseString('racecar')
'racecar' # See what I did there ;)

Something like this:
def reverseString(aStr, newStr = ''):
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[-1] #-1 returns the last element from the string
return reverseString(aStr[:-1], newStr) #slice the string up to second last char
print reverseString("foobar")
#raboof
The problem with your code is that newStr is getting re-assigned at each recursive loop to an empty string(''), you must pass the newStr value in every recursive call.
def reverseString(aStr, newStr= ''): #define a default value for newStr
if len(aStr) == 0:
return newStr
else:
newStr = newStr + aStr[len(aStr)-1] #better use aStr[-1]
return reverseString(aStr[:len(aStr)-1], newStr) #pass the new value of newStr
print reverseString("foobar")# No value is passed for newStr. So, default is used .

Just sayin', there's an easier way to do this, which avoids recursion and the problems that it entails :
>>> ''.join(reversed("abcd"))
'dcba'

You are returning the result of the recursive call, without keeping the information from previous calls. You have this line:
newStr = newStr + aStr[len(aStr)-1]
but newStr is then discarded.
Possible solution:
def reverseString(aStr):
if len(aStr) == 0:
return ''
else:
return aStr[-1] + reverseString(aStr[:-1])
or simply
def reverseString(s):
return s[-1]+reverseString(s[:-1]) if s else ''
Note that both these solutions are elegant, but are "normal" recursion, and therefore suboptimal; for a tail-recursive solution (which potentially can be optimized into a loop) see #Ashwini Chaudhary's answer.

Related

Using recursion to concatenate two strings

My goal is to concatenate two strings using recursion.
The input would be str1 = ("long string") str2 = ("yes so long")
and the output would be: 'lyoensg ssto rlionngg'
Assumptions are that both strings are the same length.
My code as of now is:
def concat_order(str1, str2):
if len(str1) == 0:
return 'complete'
i = 0
new_str = str1[i] + str2[i]
i = i + 1
return concat_order(str1[1:], str2[1:])
return new_str
print(concat_order("long string"', "yes so long"))
Im sure Im no where close but I am struggling with making it loop.
I am not allowed to use loops but I can use if statements
You don't need to pass 'i' like this: new_str = str1[i] + str2[i]
as you are already returning string excluding previous character: return concat_order(str1[1:], str2[1:]).
Also a function can not have two return statements like this:
return concat_order(str1[1:], str2[1:])
return new_str
any statement after return statement won't execute. That's why we write multiple return statements in some conditional statement like if else
Modified your program to give the correct answer.
def concat_order(str1, str2, new_str):
if len(str1) == 0:
return new_str
new_str += str1[0] + str2[0]
return concat_order(str1[1:], str2[1:], new_str)
ans = ""
print(concat_order("long string", "yes so long", ans))
or you can do this:
def concat_order(str1, str2):
if len(str1) == 0:
return ''
return str1[0] + str2[0] + concat_order(str1[1:], str2[1:])
print(concat_order("long string", "yes so long"))
as the control flow reaches base case, we already have what we wanted so don't return anything.
Recursion just needs a base case and a recursion case. Here your base case is a little strange. You never want the string "complete" so you shouldn't return that. The base case when str1 is empty should just return the empty string.
Then you just need to take the first letter from each string, concat, and concat with recursion of the rest:
def concat_order(str1, str2):
if len(str1) == 0:
return ''
a, b = str1[0], str2[0]
return a + b + concat_order(str1[1:], str2[1:])
concat_order("long string", "yes so long")
# 'lyoensg ssot rlionngg'
Note the extra space is the correct behavior unless there's a requirement to prevent them.
def concat_strings_rec(str1, str2):
if len(str1) < 1:
return ""
else:
curStr = str1[0] + str2[0]
return curStr + concat_strings_rec(str1[1:], str2[1:])
def concat_string_iter(str1, str2):
return "".join([str1[i] + str2[i] for i in range(len(str1))])
string1 = "long string"
string2 = "yes so long"
print(concat_strings_rec(string1, string2))
print(concat_string_iter(string1, string2))
Expected output:
lyoensg ssot rlionngg
lyoensg ssot rlionngg
Recursive solution
You need the base case which is when the array length is 0. In that case return an empty string. In all other cases return the first element of each string concatenated with the return value of the recursive call to concat_strings_rec(). Remember to decrease the array size for the recursive calls!
Iterative solution
The iterative solution just loops through the array concatenating each character within the two strings and putting the concatenated first, second, third,... character in an array. Then use "".join() to concatenate those two character strings in the array to a complete string.
Recommendation
Don't use the recursive solution as it just consumes more memory due to the call stack and it will be slower and since Python has a limit on the number of calls on the call stack it will fail for larger strings.

TimeLimitError when removing all occurrences of a string from another string

I'm doing an exercise in which I have to remove all occurrences of a string from another string and, although it works, it seems that the program is iterating and infinite amount of times and I can't fix it. I know there is a string.replace() function but I wanted to try to solve the problem without using the fuction.
This is the code:
'''
def remove_all(substr,theStr):
index = theStr.find(substr)
if index > 0:
newstr = ""
while index > 0:
sizsub = len(substr)
newstr = theStr[:index] + theStr[(index + len(substr)):]
index = newstr.find(substr)
return newstr
else:
return theStr
remove_all("an", "banana")
'''
the error message: "TimeLimitError: Program exceeded run time limit. on line 9"
Thanks in advance.
First, you should check if index is greater than -1, not 0, because 0 is the first index.
Inside while you are cuting the initial theStr every time ,which causes newstr to be same thing and stuck in loop.
You can solve this by giving initail value equal to theStr for newstr and cut the newstr instead of theStr inside loop.
def x(substr, theStr):
index = theStr.find(substr)
if index > -1:
newstr = theStr
while index> -1:
sizsub = len(substr)
newstr = newstr[:index] + newstr[index + sizsub:]
index = newstr.find(substr)
return newstr
else:
return theStr
print(x('an', 'banana'))
# prints => ba

iterating through STRINGS in Python (3)

: Write a function, named foldStrings(string1, string2) that takes, as arguments, two strings. If
the two strings are equal in length, the function returns a string that is formed by alternating characters in each of the two strings. If the two strings are not equal in length, the function returns the string “The two strings are not
equal in length.”
For example, >>>foldStrings(“abc”, “def”)
should return the string “adbecf” and >>>foldStrings(“a”, “bc”)
should return the string “The two strings are not equal in length.”
This is what I have so far:
def foldStrings(str1, str2):
newStr = ""
counter = 0
if len(str2) == len(str1):
while counter < len(str2):
for element in str1:
for index in str2:
newStr = newStr + element
newStr = newStr + index
counter += 1
return newStr
else:
return "The two Strings are not equal in length"
and it prints this: 's1s2s3s4s5s6a1a2a3a4a5a6n1n2n3n4n5n6t1t2t3t4t5t6o1o2o3o4o5o6s1s2s3s4s5s6'
instead of this:
's1a2n3t4o5s6'
You have unnecessarily complicated the problem with three nested loops, when a single loop is required.
Replace:
while counter < len(str2):
for element in str1:
for index in str2:
newStr = newStr + element
newStr = newStr + index
counter += 1
return newStr
With:
for index in range(len(str1)) :
newStr = newStr + str1[index] + str2[index]
return newStr
In the original code, if the string length was for example 6, your code says:
Repeat 6 times:
for every character in str1
for every character in str1
do stuff
so that do stuff is executed 6 x 6 x 6 times! You only want to execute it 6 times suggesting a single loop.
What you were doing wrong was not a python specific issue, but rather an issue with your algorithmic and logical thinking. Mathematically the problem suggests a single iteration, while you had three - nested. In this case you might have manually walked through the code or used a debugger to step through it to demonstrate flaw in thinking here.
You can skip using a counter variable by using range
def foldStrings(str1, str2):
if len(str1) != len(str2):
return "The two Strings are not equal in length"
# This should really be a raise ValueError("The two Strings are not equal in length")
newStr = ''
for i in range(len(str1)):
newStr += str1[i] + str2[i]
return newStr
Here's a slightly more compact way to replace the for loop
newStr = ''.join([x for pair in zip(str1, str2) for x in pair])
#Simple way to do it
def foldStrings(str1, str2):
newStr = ""
counter = 0
if len(str2) == len(str1):
while counter < len(str2):
newStr = newStr + str1[counter] + str2[counter]
counter += 1
return newStr
else:
return "The two Strings are not equal in length"

Replace a substring in a string with python

I am trying to replace every instance of a substring in a string using python. The following is the code that I have done and it is giving me some weird result.
def main():
s='IN GOING GO'
x='IN'
y='aa'
print(rep_str(s,x,y))
def rep_str(s,x,y):
result=""
if x in s:
for i in range(len(s)):
if s[i:i+len(x)] == x:
result=result+y
else:
result=result+s[i+1:i+len(x)]
return result
main()
I am not allowed to use the replace method. In fact, my function is supposed to do what replace function does in python. The following is the output that I am getting.
aa GOIaaG GO
I would appreciate if someone could give me some input about how to change the logic to get the right out put i.e.
aa GOaaG GO.
As I mentioned in comments, the mistake is that you are not skipping len(x) characters after match. Also in keyword is quite high-level routine (it does not less than search part of search & replace), so here is fixed version without in:
def rep_str(string, search, replacement):
result = ''
i = 0
while i < len(string):
if string[i : i + len(search)] == search:
result += replacement
i += len(search)
else:
result += string[i]
i += 1
return result
If you just want to have the result try with:
import re
re.sub(r'IN','aa','IN GOING GO')
but if you need some logic then you should compare for blocks of same length as the pattern, not char by char
#Zag asnwer is better, because can compare longer patterns and has return when it does not match nothing but if you want to get your code running you need to skip for when you have a match like this :
def rep_str(s,x,y):
result=""
skip = False
if x in s:
for i in range(len(s)):
if skip:
skip = False
continue
if s[i:i+2] == x:
result+=y
skip = True
else:
result+=s[i:i+1]
return result
else:
return s
but your code won't work when you will call the function with rep_str("A example test","test", "function") for example.
If you are allow to use the index() function, you can try this:
def main():
s='IN GOING GO'
x='IN'
y='aa'
print(rep_str(s,x,y))
def rep_str(s,x,y):
while x in s:
s = s[:s.index(x)] + y + s[s.index(x) + len(x):]
return s
main()

Python 3.2 palindrome

I'm doing some python online tutorials, and I got stuck at an exercise:A palindrome is a word which is spelled the same forwards as backwards. For example, the word
racecar
is a palindrome: the first and last letters are the same (r), the second and second-last letters are the same (a), etc. Write a function isPalindrome(S) which takes a string S as input, and returns True if the string is a palindrome, and False otherwise.
These is the code I wrote :
def isPalindrome(S):
if S[0] == S[-1]
return print("True")
elif S[0] == S[-1] and S[1] == S[-2] :
return print("True")
else:
return print("False")
But, if the word is for example ,,sarcas,, , the output is incorect. So I need a fix to my code so it works for any word.
A one line solution but O(n) and memory expensive is :
def isPalindrome(word) : return word == word[::-1]
A O(n/2) solution that uses the same amount of memory is:
def palindrome(word):
for i in range(len(word)//2):
if word[i] != word[-1-i]:
return False
return True
This is the trick #LennartRegebro mentioned
def is_palindrome(text):
text = text.replace(' ', '')
text = text.casefold()
if list(text) == list(reversed(text)):
return True
else:
return False
Try this
word='malayalam'
print(word==word[::-1])
The best way to check a word is palindrome or not in Python is as below:
var[::] == var[::-1]
But, it is very important to understand that Python creates a new copy of string when you do var[::-1]
Python internally don't know if the reverse will result in same string or not. So, it's coded in a way where it creates a new copy of it.
So, when you try var[::1] is var[::-1] you will get FALSE.
Here is my solution.
S = input("Input a word: ")
def isPalindrome(S):
for i in range(0, len(S)):
if S[0 + i] == S[len(S) - 1]:
return "True"
else:
return "False"
print(isPalindrome(S))
Here's my solution:
def isPalindrome(S):
l = len(S)-1
for i in range(0,l):
if S[i]!=S[l-i]:
return False
return True
Another way of doing it using recursion is:
def isPalindrome(word):
if len(word) <= 1: return True
return (word[0] == word[-1]) and isPalindrome(word[1:-1])
this is my solution
S = input("Input a word: ")
def isPalindrome(S):
for i in range(0, len(S)):
if S[0 + i] == S[len(S) - 1]:
return "True"
else:
return "False"
print(isPalindrome(S))
This is beaten to death, but I have some ideas if Python is implemented in C. If ...
The code word[::-1] iterates to string end to make a copy which discounts the word == word[::-1] code speed and memory efficiency factors
Iteration to the word middle is better then comparing a full word as characters were already tested - for odd words the middle letter is not to be tested
Additions and subtractions need to be used sparingly
Recursion is cool (and fun), but uses a lot of stack (unless optimized with tail recursion ... which likely becomes a for loop in the underlying code but less likely able to be flexible enough to impose code optimizations).
Bit shifts are traditionally faster than divides
The following is the code:
def isPalindrome(S):
last = len(S)
middle = last >> 1
for i in range(middle):
last -= 1
if(S[i] != S[last]):
return False
return(True)
print("\n".join([str((word, isPalindrome(word))) for word in ["abcdcba", "abcdBba", "abccba", "abcBba", "a", ""]]))
which yields:
('abcdcba', True)
('abcdBba', False)
('abccba', True)
('abcBba', False)
('a', True)
('', True)

Categories

Resources