I am solving a algorithm problem on LeetCode (5th problem if you want to read the problem first
https://leetcode.com/problems/longest-palindromic-substring/).
I wrote a python program:
class Solution(object):
def longestPalindrome(self, s):
"""
:type s: str
:rtype: str
"""
l = 1
if len(s) < 2:
return s
result = s[0]
for end in range(1, len(s)):
if end - (l + 1) >= 0 and s[end - (l + 1):end + 1] == s[end - (l + 1):end + 1][::-1]:
l += 2
result = s[end - (l + 1):end + 1]
continue
elif end - l >= 0 and s[end - l:end + 1] == s[end - l:end + 1][::-1]:
l += 1
result = s[end-l:end+1]
return result
When I test it using 'abba' as input: it outputs 'ba'.
Then, I found a python solution in the discussion, the program looks like this:
class Solution:
# #return a string
def longestPalindrome(self, s):
if len(s) == 0: return 0
maxLen = 1
start = 0
for i in xrange(len(s)):
if i - maxLen >= 1 and s[i - maxLen - 1:i + 1] == s[i - maxLen - 1:i + 1][::-1]:
start = i - maxLen - 1
maxLen += 2
continue
if i - maxLen >= 0 and s[i - maxLen:i + 1] == s[i - maxLen:i + 1][::-1]:
start = i - maxLen
maxLen += 1
return s[start:start + maxLen]
When I test it using 'abba' as input, it outputs 'abba' correctly.
I am a pretty new beginner in python, so I always get confused by the matter of passing parameters in python. So, could anyone tell me why the two python programs get two different results?
Thanks in advance.
You change l between where you determine there is a palindrome and where you use l to assign that palindrome to result. In both places.
Related
I'm trying to solve leetcode problem 4 which needs you to do binary search.
Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.
The overall run time complexity should be O(log (m+n)).
This is my code:
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
if len(nums1) > len(nums2):
return self.findMedianSortedArrays(nums2, nums1)
A, B = nums1, nums2
total = len(A) + len(B)
half = total // 2
l, r = 0, len(A) - 1
while l < r:
i = l + (r - l) // 2
j = half - i - 1 - 1
Aleft = A[i] if i >= 0 else float("-inf")
Aright = A[i + 1] if (i + 1) < len(A) else float("inf")
Bleft = B[j] if j >= 0 else float("-inf")
Bright = B[j + 1] if (j + 1) < len(B) else float("inf")
if Aleft <= Bright and Bleft <= Aright:
if total % 2:
return min(Aright, Bright)
else:
return (max(Aleft, Bleft) + min(Aright, Bright)) / 2
elif Aleft > Bright:
r = i - 1
elif Bleft > Aright:
l = i + 1
It gives this error note:
TypeError: None is not valid value for the expected return type double
raise TypeError(str(ret) + " is not valid value for the expected return type double");
Line 52 in _driver (Solution.py)
_driver()
Line 59 in <module> (Solution.py)
During handling of the above exception, another exception occurred:
TypeError: must be real number, not NoneType
Line 18 in _serialize_float (./python3/__serializer__.py)
Line 61 in _serialize (./python3/__serializer__.py)
out = ser._serialize(ret, 'double')
Line 50 in _driver (Solution.py)
However if I change the while loop condition to just while True:
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
if len(nums1) > len(nums2):
return self.findMedianSortedArrays(nums2, nums1)
A, B = nums1, nums2
total = len(A) + len(B)
half = total // 2
l, r = 0, len(A) - 1
while True:
i = l + (r - l) // 2
j = half - i - 1 - 1
Aleft = A[i] if i >= 0 else float("-inf")
Aright = A[i + 1] if (i + 1) < len(A) else float("inf")
Bleft = B[j] if j >= 0 else float("-inf")
Bright = B[j + 1] if (j + 1) < len(B) else float("inf")
if Aleft <= Bright and Bleft <= Aright:
if total % 2:
return min(Aright, Bright)
else:
return (max(Aleft, Bleft) + min(Aright, Bright)) / 2
elif Aleft > Bright:
r = i - 1
elif Bleft > Aright:
l = i + 1
It runs perfectly.
Why the difference? How could these two different in logic?
Any help will be much appreciated.
The error you see is a little obscure because LeetCode is taking your solution code and wrapping it up for execution - but 1 hint you can tell from the error is that something is returning None when it's expecting a double.
The thing that's different is that if l >= r, none of the code in the while block will execute and the function will return with an implicit None value. If you instead change to while True:, the code within will always execute at least once and if the code falls into Aleft <= Bright and Bleft <= Aright, then the function will return with a non-None value.
if you add a return <some-number-here> after the while loop at the end of the function, you won't get the same error however you won't have the right answer either since the failing test case will probably return with whatever value you hardcoded in.
In the default test case, you can see that this happens at some point in your code because l, r = 0, 0 if you add a print(l, r) at the end of the function(outside of the while loop) followed by the dummy return value.
My advice (and I know some IDEs warn about this as well) would be to use explicit returns if a function is expected to return something and try not to force consumers of your function to handle None if you can - consistent types make for happy programmers.
I am trying to find the longest Palidromic Substring of a given string, LeetCode problem.
I am getting a lesser runtime for expanding centers even though its time complexity is N**2 and manachers is N.
What mistake am I making?
'''
Manachers Algorithm O(N) ---> runtime 2000ms
class Solution(object):
def addhashspace(self,s: str) -> str:
t = ''
for i in range(len(s)):
t += '#' + s[i]
t = '$' + t + '##'
return t
def longestPalindrome(self, s: str) -> str:
t = self.addhashspace(s)
P = [0]*len(t)
maxi = 0
for i in range(len(t)-1):
C,R = 0,0
mirr = 2*C - 1
if(i< R):
P[i] = min(P[mirr],R - i)
while(t[i + P[i] + 1] == t[i - P[i] - 1]):
P[i] += 1
if(i + P[i] > R):
C = i
R = i + P[i]
if P[i] > maxi:
maxi = P[i]
index = i
ind1 = index//2 - P[index]//2 - maxi%2
ind2 = index//2 + P[index]//2
return(s[ind1:ind2])
Expnding centers O(N**2) ----> 800ms
class Solution(object):
def longestPalindrome(self, s: str) -> str:
startt = time.time()
if len(s) <= 1:
return s
start = end = 0
length = len(s)
for i in range(length):
max_len_1 = self.get_max_len(s, i, i + 1)
max_len_2 = self.get_max_len(s, i, i)
max_len = max(max_len_1, max_len_2)
if max_len > end - start:
start = i - (max_len - 1) // 2
end = i + max_len // 2
print("Execution Time of 2nd Algo " + str((time.time() - startt) * 10**6) + " ms")
return s[start: end+1]
def get_max_len(self, s: 'list', left: 'int', right: 'int') -> 'int':
length = len(s)
i = 1
max_len = 0
while left >= 0 and right < length and s[left] == s[right]:
left -= 1
right += 1
return right - left - 1
"civilwartestingwhetherthatnaptionoranynartionsoconceivedandsodedicatedcanlongendureWeareqmetonagreatbattlefiemldoftzhatwarWehavecometodedicpateaportionofthatfieldasafinalrestingplaceforthosewhoheregavetheirlivesthatthatnationmightliveItisaltogetherfangandproperthatweshoulddothisButinalargersensewecannotdedicatewecannotconsecratewecannothallowthisgroundThebravelmenlivinganddeadwhostruggledherehaveconsecrateditfaraboveourpoorponwertoaddordetractTgheworldadswfilllittlenotlenorlongrememberwhatwesayherebutitcanneverforgetwhattheydidhereItisforusthelivingrathertobededicatedheretotheulnfinishedworkwhichtheywhofoughtherehavethusfarsonoblyadvancedItisratherforustobeherededicatedtothegreattdafskremainingbeforeusthatfromthesehonoreddeadwetakeincreaseddevotiontothatcauseforwhichtheygavethelastpfullmeasureofdevotionthatweherehighlyresolvethatthesedeadshallnothavediedinvainthatthisnationunsderGodshallhaveanewbirthoffreedomandthatgovernmentofthepeoplebythepeopleforthepeopleshallnotperishfromtheearth"
This is the worst case test input among other inputs I was using to compare the two algorithms. I used a counter to see the number of iterations it took to find the palindrome "ranynar" in the given string.
Not shockingly - Manachers took 1189 iterations where as Expanding Centers took 1094 iterations.
Definitely Manachers takes more computational time in each iteration so that explains the runtime difference.
I guess my test input size has been small to really take advantage of O(N) time complexity as Manachers does require more steps in each iteration.
I will have to test with a dataset with larger input sizes to see the difference in the two.
I am new to python and trying to learn some codes. This is my first programming attempt with python. I have a sequence S and a sequence T(which is also a relation of a couples recurrence relationship equation)where
Sn= 2S(n-1)+S(n-2)+4T(n-1)
and T=S(n-1)+T(n-1).
S0=1, S1=2, T0=0 AND T1=1.
How can i write a function that returns nth value of S and T sequence where the function takes n as a parameter and returns Sn,Tn as a tuple as result of calling the function?
Here are the recursive functions:
def T(n):
if n == 0:
return 0
if n == 1:
return 1
return S(n - 1) + T(n - 1)
def S(n):
if n == 0:
return 1
if n == 1:
return 2
return 2 * S(n - 1) + S(n - 2) + 4 * T(n - 1)
def tuple_func(n):
return(S(n), T(n))
Somewhere between n == 20 and n == 30 this becomes ridiculously slow, depending on your threshold for ridiculousness.
"For fun" I've converted the recursive functions to an iterative version. On my computer it can do up to n == 50,000 in about a second.
def tuple_func(n):
S = [1, 2]
T = [0, 1]
if n < 0:
return(None, None)
if 0 >= n < 2:
return(S[n], T[n])
for n in range(2, n + 1):
S.append(2 * S[n - 1] + S[n - 2] + 4 * T[n - 1])
T.append(S[n - 1] + T[n - 1])
return(S[n], T[n])
I have written Smith-Waterman like algorithm and it is leaking
Here is my leaking fragment of code:
for row in range(1, n + 1):
for col in range(1, m + 1):
left = table[row][col - 1] - 1
up = table[row - 1][col] - 1
upLeft = table[row - 1][col - 1] + s(seq1[col - 1], seq2[row - 1])
table[row][col] = max(left, up, upLeft)
The last line leaks.
How to copy only value not use reference, or what I should do with this inside list reference?
Other question is how to optimize this algorithm to use only 2 columns/rows, but it's not difficult probably. First I want to know why the code leaking.
Full code:
def smith_waterman(seq1, seq2):
"""
:rtype : float
:return: folat
:param seq1: list of 0,1,2
:param seq2: list of 0,1,2
"""
m = len(seq1)
n = len(seq2)
def s(a, b):
"""
:param a: 0,1,2
:param b: 0,1,2
:return: iteger
"""
c = a + b
if a == b:
return 2
elif c == 3:
return 1
elif c == 2:
return 2
else:
return -1
# create empty table
table = []
for i in range(n + 1):
table.append([])
for j in range(m + 1):
table[i].append(0)
for row in range(1, n + 1):
for col in range(1, m + 1):
left = table[row][col - 1] - 1
up = table[row - 1][col] - 1
upLeft = table[row - 1][col - 1] + s(seq1[col - 1], seq2[row - 1])
table[row][col] = max(left, up, upLeft)
return table[n][m]) / (n + m)
What do you mean with "leaking"? Are you referring to the fact that your algorithm uses more memory than expected? If this is the case, then it could be related to your table definition vs. its usage: you're allocating an n x m table, whereas you're using just (n-1) x (m-1) items.
Try changing your loops from range(1, n+1) to range(n), making the similar change for the second index (and updating the index usages of course).
I am trying to create a program which will receive two strings and compeer between, and returns the largest common letters in the order they appear.
examples:
string1="a" string2="b"
return ""
string1="abc" string2="ac"
return "ac"
string1:“abcd” string2:“ acdbb”
return:“ abcd"
I need to write 3 codes - "normal way", recursive way and "in memorization" way.
So far I've succeed to code:
def l_c_s(s1, s2):
for i in range(1 + len(s1))]:
mi = [[0] * (1 + len(s2))
long, x_long = 0, 0
for x in range(1, 1 + len(s1)):
for y in range(1, 1 + len(s2)):
if s1[x - 1] == s2[y - 1]:
m[x][y] = m[x - 1][y - 1] + 1
if m[x][y] > long:
long = m[x][y]
x_long = x
m[x][y] = 0
return s1[x_long - long: x_long]
But I don't get what I wanted. just run this code for the string1="abc" string2="ac"
and the see what happens.
Moreover, I have no idea how to make it recursive and neither to write it in memo.
If what you want is really longest common sub-sequence, here is a version using memoization:
s1 = 'abcdd'
s2 = 'add'
mem = [[-1] * len(s2)] * len(s1)
matched = []
def lcs(i,j):
if i < 0 or j < 0:
return 0
if mem[i][j] >= 0:
return mem[i][j]
if s1[i] == s2[j]:
p = 1 + lcs(i-1, j-1)
if p > mem[i][j]:
mem[i][j] = p
matched.append(s1[i])
return max(mem[i][j], lcs(i-1, j), lcs(i, j-1))
lcs_length = lcs(len(s1)-1, len(s2)-1)
lcs = "".join(matched)
print 'LCS: <%s> of length %d' % (lcs, lcs_length)