Finding the longest alphabetical substring in a longer string - python

This code finds the longest alphabetical substring in a string (s).
letter = s[0]
best = ''
for n in range(1, len(s)):
if len(letter) > len(best):
best = letter
if s[n] >= s[n-1]:
letter += s[n]
else:
letter = s[n]
It works most of the time, but occasionally it gives wrong answers and I am confused why it only works sometimes. for example when:
s='maezsibmhzxhpprvx'
It said the answer was "hpprv" while it should have been "hpprvx".
In another case, when
s='ysdxvkctcpxidnvaepz'
It gave the answer "cpx", when it should have been "aepz".
Can anyone make sense of why it does this?

You should move this check
if len(letter) > len(best):
best = letter
after the rest of the loop

Your routine was almost ok, here's a little comparison between yours, the fixed one and another possible solution to your problem:
def buggy(s):
letter = s[0]
best = ''
for n in range(1, len(s)):
if len(letter) > len(best):
best = letter
if s[n] >= s[n - 1]:
letter += s[n]
else:
letter = s[n]
return best
def fixed(s):
letter = s[0]
best = ''
for n in range(1, len(s)):
if s[n] >= s[n - 1]:
letter += s[n]
else:
letter = s[n]
if len(letter) > len(best):
best = letter
return best
def alternative(s):
result = ['' for i in range(len(s))]
index = 0
for i in range(len(s)):
if (i == len(s) - 1 and s[i] >= s[i - 1]) or s[i] <= s[i + 1]:
result[index] += s[i]
else:
result[index] += s[i]
index += 1
return max(result, key=len)
for sample in ['maezsibmhzxhpprvx', 'ysdxvkctcpxidnvaepz']:
o1, o2, o3 = buggy(sample), fixed(sample), alternative(sample)
print "buggy={0:10} fixed={1:10} alternative={2:10}".format(o1, o2, o3)
As you can see in your version the order of the inner loop conditional is not good, you should move the first conditional to the end of loop.

The logic is almost okay except that if letter grows on the last loop iteration (when n == len(s) - 1), best is not changed that last time. You may insert another best = letter part after the loop, or re-think carefully the program structure so you won't repeat yourself.

Related

Count amount of comparison using naive string matching algorithm python

In my code I try to found index of the pattern, count every comparison and I also want to stop this algorithm then my pattern is too long for comparison to rest of the text. Something is wrong with counter and I couldn't stop algorithm. I am beginner and I don't have idea what to do.
def search(W, T):
count = 0
for i in range(len(T) - len(W) + 1):
if i > len(T)-len(W):
break
j = 0
while(j < len(W)):
if (T[i + j] != W[j]):
count += 1
break
j += 1
if (j == len(W)):
count += len(W)
print("Pattern found at index ", i, count)
if __name__ == '__main__':
T = "AABAACAADAABAAABAA"
W = "AABA"
search(W, T)
Thanks for helping.
I expect that someone will change my code or tell me what to do.
First of all, as you are a beginner in Python here's some tips:
You do not need brackets in if: if j == len(W): is ok, moreover these brackets are against PEP8 codestyle.
You don't need this condition:
if i > len(T)-len(W):
break
range() is smart guy. He won't let i be more then len(T)-len(W)
Now to your question, here's the solution (I hope, that I understand what do you want)
def search(W, T):
count = 0
for i in range(len(T) - len(W) + 1):
j = 0
while j < len(W):
if T[i + j] != W[j]:
count += 1
break
j += 1
count += 1
if j == len(W):
print("Pattern found at index ", i, count)
if __name__ == '__main__':
T = "AABAACAADAABAAABAA"
W = "AABA"
search(W, T)
The problem was that you increment your counter only when you founded the pattern or when you failed to find it. Here's example:
T = AAABAAA
W = AABA
In your solution counter would be incremented only on the 3d letter "A" while it should be incremented after each comparison.
I hope everything is clear. Good luck in studying!

Python: how to optimize this code for better performance

I use this code to syllable a list of strings, I need to be able to speed up this code to pass some tests, any ideas to improve this code and make it faster?
def separate(word):
s = ""
L = []
voc = ['a','e','i','o','u','y','j']
for letter in word:
if len(s) < 1:
s += letter
elif s[len(s) - 1] not in voc:
s += letter
elif s.startswith('aeiouyj'):
s +=letter
elif letter in voc:
s += letter
else:
L.append(s)
s = letter
L.append(s)
return L
Did some small misc adjustments.
def separate(word):
s=''
L = []
for letter in word:
if s=='':
s = letter
elif s[-1] not in 'aeiouyj' or letter in 'aeiouyj':
s += letter
else:
L.append(s)
s = letter
L.append(s)
return L
Not sure if s.startswith('aeiouyj') is of any use in original code because it never going to be True.
def separate(word):
s = ""
L = []
voc = ['a','e','i','o','u','y','j']
s=word[0]
for letter in word[1:]:
if s[len(s) - 1] not in voc:
s += letter
elif letter in voc or s.startswith('aeiouyj'):
s +=letter
else:
L.append(s)
s = letter
L.append(s)
return L
After analysing the code, we can see that it is going into first if just in the beginning. So, we can skip this part. One more thing you can do bring the if before last else to the second place. After analysing a Harry Potter paragraph with this program it enters into loops "1,2436,0,98,959" times respectively. The third if maybe eliminated too, since it never entered into this branch in my case.
Instead of using loops you can use recursion which is faster than it. Also Functional programming is always preferred as it is based on input.

How to count the number of vowels in a string without a function wrapper

I've currently solving a MIT undergrad problem in Python 3.5.
The goal is to write a Python script counting and printing the number of vowels in a string containing only lower-case letters without using a function wrapper or even a function definition (stated in the assignment, weird ?).
def vowels_count(s):
i=0
counter = 0
while(s[i] != " "):
if s[i] == "a" or s[i] == "e" or s[i] == "i" or s[i] == "o" or s[i] == "u":
counter += 1
i = i + 1
return(counter)
I have two problems:
1/ first of, my own code using a while do structure meets a problem with the use of the index navigating from the first character to the last one. The debugger says: index out of range
2/ finally, if I have to comply with the MIT instructions, I would not be able to do anything in a single-line code without defining a function.
Thanks for your support
Why is this version not correct on the string index i ?
def vowels_count_1(s):
i = 0
counter = 0
while(s[i] != ""):
if s[i] == "a" or s[i] == "e" or s[i] == "i" or s[i] == "o" or s[i] == "u":
counter += 1
i += 1
print("Number of vowels: " + str(counter))
You can use the condition of i being less than the length of your string to break out of the while loop. I also recommend the easier approach of just checking if the letter at s[i] is in a string composed of vowels:
def vowels_count(s):
i = 0
counter = 0
while i < len(s):
if s[i] in 'aeiou':
counter += 1
i += 1
return counter
If you wanted to do this in one line, you could use the length of a list comprehension:
counter = len([c for c in s if c in 'aeiou'])
As you learn more and more you'll be able to count the vowels in one line using sum and a generation expression.
You could fix your loop while i < len(s), i.e. up to the length of the string, but much better is just to iterate over the sequence of characters we call "string".
for ch in s:
if ch == 'a' or ...
No indices needed. No i.
If you have learned the in operator already, you could simplify the test.
Without a function probably means this:
s = "the string"
# your code here
print("vowel count:", counter)
But I'm not sure ...
Here is an one line solution:
reduce(lambda t, c : (t + 1) if c in 'aeiou' else t, s.lower(), 0)

Find the longest substring in alphabetical order

I have this code that I found on another topic, but it sorts the substring by contiguous characters and not by alphabetical order. How do I correct it for alphabetical order? It prints out lk, and I want to print ccl. Thanks
ps: I'm a beginner in python
s = 'cyqfjhcclkbxpbojgkar'
from itertools import count
def long_alphabet(input_string):
maxsubstr = input_string[0:0] # empty slice (to accept subclasses of str)
for start in range(len(input_string)): # O(n)
for end in count(start + len(maxsubstr) + 1): # O(m)
substr = input_string[start:end] # O(m)
if len(set(substr)) != (end - start): # found duplicates or EOS
break
if (ord(max(sorted(substr))) - ord(min(sorted(substr))) + 1) == len(substr):
maxsubstr = substr
return maxsubstr
bla = (long_alphabet(s))
print "Longest substring in alphabetical order is: %s" %bla
s = 'cyqfjhcclkbxpbojgkar'
r = ''
c = ''
for char in s:
if (c == ''):
c = char
elif (c[-1] <= char):
c += char
elif (c[-1] > char):
if (len(r) < len(c)):
r = c
c = char
else:
c = char
if (len(c) > len(r)):
r = c
print(r)
Try changing this:
if len(set(substr)) != (end - start): # found duplicates or EOS
break
if (ord(max(sorted(substr))) - ord(min(sorted(substr))) + 1) == len(substr):
to this:
if len(substr) != (end - start): # found duplicates or EOS
break
if sorted(substr) == list(substr):
That will display ccl for your example input string. The code is simpler because you're trying to solve a simpler problem :-)
You can improve your algorithm by noticing that the string can be broken into runs of ordered substrings of maximal length. Any ordered substring must be contained in one of these runs
This allows you to just iterate once through the string O(n)
def longest_substring(string):
curr, subs = '', ''
for char in string:
if not curr or char >= curr[-1]:
curr += char
else:
curr, subs = '', max(curr, subs, key=len)
return max(curr, subs, key=len)
s = 'cyqfjhcclkbxpbojgkar'
longest = ""
max =""
for i in range(len(s) -1):
if(s[i] <= s[i+1] ):
longest = longest + s[i]
if(i==len(s) -2):
longest = longest + s[i+1]
else:
longest = longest + s[i]
if(len(longest) > len(max)):
max = longest
longest = ""
if(len(s) == 1):
longest = s
if(len(longest) > len(max)):
print("Longest substring in alphabetical order is: " + longest)
else:
print("Longest substring in alphabetical order is: " + max)
In a recursive way, you can import count from itertools
Or define a same method:
def loops( I=0, S=1 ):
n = I
while True:
yield n
n += S
With this method, you can obtain the value of an endpoint, when you create any substring in your anallitic process.
Now looks the anallize method (based on spacegame issue and Mr. Tim Petters suggestion)
def anallize(inStr):
# empty slice (maxStr) to implement
# str native methods
# in the anallize search execution
maxStr = inStr[0:0]
# loop to read the input string (inStr)
for i in range(len(inStr)):
# loop to sort and compare each new substring
# the loop uses the loops method of past
# I = sum of:
# (i) current read index
# (len(maxStr)) current answer length
# and 1
for o in loops(i + len(maxStr) + 1):
# create a new substring (newStr)
# the substring is taked:
# from: index of read loop (i)
# to: index of sort and compare loop (o)
newStr = inStr[i:o]
if len(newStr) != (o - i):# detect and found duplicates
break
if sorted(newStr) == list(newStr):# compares if sorted string is equal to listed string
# if success, the substring of sort and compare is assigned as answer
maxStr = newStr
# return the string recovered as longest substring
return maxStr
Finally, for test or execution pourposes:
# for execution pourposes of the exercise:
s = "azcbobobegghakl"
print "Longest substring in alphabetical order is: " + anallize( s )
The great piece of this job started by: spacegame and attended by Mr. Tim Petters, is in the use of the native str methods and the reusability of the code.
The answer is:
Longest substring in alphabetical order is: ccl
In Python character comparison is easy compared to java script where the ASCII values have to be compared. According to python
a>b gives a Boolean False and b>a gives a Boolean True
Using this the longest sub string in alphabetical order can be found by using the following algorithm :
def comp(a,b):
if a<=b:
return True
else:
return False
s = raw_input("Enter the required sting: ")
final = []
nIndex = 0
temp = []
for i in range(nIndex, len(s)-1):
res = comp(s[i], s[i+1])
if res == True:
if temp == []:
#print i
temp.append(s[i])
temp.append(s[i+1])
else:
temp.append(s[i+1])
final.append(temp)
else:
if temp == []:
#print i
temp.append(s[i])
final.append(temp)
temp = []
lengths = []
for el in final:
lengths.append(len(el))
print lengths
print final
lngStr = ''.join(final[lengths.index(max(lengths))])
print "Longest substring in alphabetical order is: " + lngStr
Use list and max function to reduce the code drastically.
actual_string = 'azcbobobegghakl'
strlist = []
i = 0
while i < len(actual_string)-1:
substr = ''
while actial_string[i + 1] > actual_string[i] :
substr += actual_string[i]
i += 1
if i > len(actual_string)-2:
break
substr += actual-string[i]
i += 1
strlist.append(subst)
print(max(strlist, key=len))
Wow, some really impressing code snippets here...
I want to add my solution, as I think it's quite clean:
s = 'cyqfjhcclkbxpbojgkar'
res = ''
tmp = ''
for i in range(len(s)):
tmp += s[i]
if len(tmp) > len(res):
res = tmp
if i > len(s)-2:
break
if s[i] > s[i+1]:
tmp = ''
print("Longest substring in alphabetical order is: {}".format(res))
Without using a library, but using a function ord() which returns ascii value for a character.
Assumption: input will be in lowercase, and no special characters are used
s = 'azcbobobegghakl'
longest = ''
for i in range(len(s)):
temp_longest=s[i]
for j in range(i+1,len(s)):
if ord(s[i])<=ord(s[j]):
temp_longest+=s[j]
i+=1
else:
break
if len(temp_longest)>len(longest):
longest = temp_longest
print(longest)
Slightly different implementation, building up a list of all substrings in alphabetical order and returning the longest one:
def longest_substring(s):
in_orders = ['' for i in range(len(s))]
index = 0
for i in range(len(s)):
if (i == len(s) - 1 and s[i] >= s[i - 1]) or s[i] <= s[i + 1]:
in_orders[index] += s[i]
else:
in_orders[index] += s[i]
index += 1
return max(in_orders, key=len)
s = "azcbobobegghakl"
ls = ""
for i in range(0, len(s)-1):
b = ""
ss = ""
j = 2
while j < len(s):
ss = s[i:i+j]
b = sorted(ss)
str1 = ''.join(b)
j += 1
if str1 == ss:
ks = ss
else:
break
if len(ks) > len(ls):
ls = ks
print("The Longest substring in alphabetical order is "+ls)
This worked for me
s = 'cyqfjhcclkbxpbojgkar'
lstring = s[0]
slen = 1
for i in range(len(s)):
for j in range(i,len(s)-1):
if s[j+1] >= s[j]:
if (j+1)-i+1 > slen:
lstring = s[i:(j+1)+1]
slen = (j+1)-i+1
else:
break
print("Longest substring in alphabetical order is: " + lstring)
Output: Longest substring in alphabetical order is: ccl
input_str = "cyqfjhcclkbxpbojgkar"
length = len(input_str) # length of the input string
iter = 0
result_str = '' # contains latest processed sub string
longest = '' # contains longest sub string alphabetic order
while length > 1: # loop till all char processed from string
count = 1
key = input_str[iter] #set last checked char as key
result_str += key # start of the new sub string
for i in range(iter+1, len(input_str)): # discard processed char to set new range
length -= 1
if(key <= input_str[i]): # check the char is in alphabetic order
key = input_str[i]
result_str += key # concatenate the char to result_str
count += 1
else:
if(len(longest) < len(result_str)): # check result and longest str length
longest = result_str # if yes set longest to result
result_str = '' # re initiate result_str for new sub string
iter += count # update iter value to point the index of last processed char
break
if length is 1: # check for the last iteration of while loop
if(len(longest) < len(result_str)):
longest = result_str
print(longest);
finding the longest substring in alphabetical order in Python
in python shell 'a' < 'b' or 'a' <= 'a' is True
result = ''
temp = ''
for char in s:
if (not temp or temp[-1] <= char):
temp += char
elif (temp[-1] > char):
if (len(result) < len(temp)):
result = temp
temp = char
if (len(temp) > len(result)):
result = temp
print('Longest substring in alphabetical order is:', result)
s=input()
temp=s[0]
output=s[0]
for i in range(len(s)-1):
if s[i]<=s[i+1]:
temp=temp+s[i+1]
if len(temp)>len(output):
output=temp
else:
temp=s[i+1]
print('Longest substring in alphabetic order is:' + output)
I had similar question on one of the tests on EDX online something. Spent 20 minutes brainstorming and couldn't find solution. But the answer got to me. And it is very simple. The thing that stopped me on other solutions - the cursor should not stop or have unique value so to say if we have the edx string s = 'azcbobobegghakl' it should output - 'beggh' not 'begh'(unique set) or 'kl'(as per the longest identical to alphabet string). Here is my answer and it works
n=0
for i in range(1,len(s)):
if s[n:i]==''.join(sorted(s[n:i])):
longest_try=s[n:i]
else:
n+=1
In some cases, input is in mixed characters like "Hello" or "HelloWorld"
**Condition 1:**order determination is case insensitive, i.e. the string "Ab" is considered to be in alphabetical order.
**Condition 2:**You can assume that the input will not have a string where the number of possible consecutive sub-strings in alphabetical order is 0. i.e. the input will not have a string like " zxec ".
string ="HelloWorld"
s=string.lower()
r = ''
c = ''
last=''
for char in s:
if (c == ''):
c = char
elif (c[-1] <= char):
c += char
elif (c[-1] > char):
if (len(r) < len(c)):
r = c
c = char
else:
c = char
if (len(c) > len(r)):
r = c
for i in r:
if i in string:
last=last+i
else:
last=last+i.upper()
if len(r)==1:
print(0)
else:
print(last)
Out:elloW
```python
s = "cyqfjhcclkbxpbojgkar" # change this to any word
word, temp = "", s[0] # temp = s[0] for fence post problem
for i in range(1, len(s)): # starting from 1 not zero because we already add first char
x = temp[-1] # last word in var temp
y = s[i] # index in for-loop
if x <= y:
temp += s[i]
elif x > y:
if len(temp) > len(word): #storing longest substring so we can use temp for make another substring
word = temp
temp = s[i] #reseting var temp with last char in loop
if len(temp) > len(word):
word = temp
print("Longest substring in alphabetical order is:", word)
```
My code store longest substring at the moment in variable temp, then compare every string index in for-loop with last char in temp (temp[-1]) if index higher or same with (temp[-1]) then add that char from index in temp. If index lower than (temp[-1]) checking variable word and temp which one have longest substring, after that reset variable temp so we can make another substring until last char in strings.
s = 'cyqfjhcclkbxpbojgkar'
long_sub = '' #longest substring
temp = '' # temporarily hold current substr
if len(s) == 1: # if only one character
long_sub = s
else:
for i in range(len(s) - 1):
index = i
temp = s[index]
while index < len(s) - 1:
if s[index] <= s[index + 1]:
temp += s[index + 1]
else:
break
index += 1
if len(temp) > len(long_sub):
long_sub = temp
temp = ''
print(long_sub)
For comprehensibility, I also add this code snippet based on regular expressions. It's hard-coded and seems clunky. On the other hand, it seems to be the shortest and easiest answer to this problem. And it's also among the most efficient in terms of runtime complexity (see graph).
import re
def longest_substring(s):
substrings = re.findall('a*b*c*d*e*f*g*h*i*j*k*l*m*n*o*p*q*r*s*t*u*v*w*x*y*z*', s)
return max(substrings, key=len)
(Unfortunately, I'm not allowed to paste a graph here as a "newbie".)
Source + Explanation + Graph: https://blog.finxter.com/python-how-to-find-the-longest-substring-in-alphabetical-order/
Another way:
s = input("Please enter a sentence: ")
count = 0
maxcount = 0
result = 0
for char in range(len(s)-1):
if(s[char]<=s[char+1]):
count += 1
if(count > maxcount):
maxcount = count
result = char + 1
else:
count = 0
startposition = result - maxcount
print("Longest substring in alphabetical order is: ", s[startposition:result+1])

Python skipping my if statement

For some reason, this code doesn't work:
def pyglatin(word):
output = ""
wordlenedit = len(word)-1
wordlen = len(word)
fixer = 0
while fixer == 0:
for i in word:
if i == 'a' or i == 'e' or i == 'o' or i == 'i' or i == 'u':
fixer = 1
else:
wordlenedit -= 1
else:
output = word[wordlenedit:wordlen:1] + '-' + word[0:wordlenedit:1] + 'ay'
return output
To see the issues, click here. The problem appears to be that it's skipping the if statement that identifies vowels, but I'm not sure why. This results in some very odd outputs.
Your function does not work because you walk through the word, decrementing the splitting index for each consonant you encounter, starting at wordlenedit = len(word)-1.
At the end of your for loop, wordlenedit is equal to (length of the word) - 1 - (number of consonants). The function will only work if the first index of vowel in the word (starting at 0) is equal to the number of vowels - 1.
Also, the while loop is useless here, as you walk through the entire word in the for loop. It is even worse than that: the while loop will be an infinite loop if you have a word with no vowels (like "fly", as you don't check the "y")
This is a corrected version of your function, using the keyword break:
def pyglatin2(word):
output = ""
wordlenedit = 0
wordlen = len(word)
for l in word:
if l == 'a' or l == 'e' or l == 'o' or l == 'i' or l == 'u':
break
else:
wordlenedit += 1
output = word[wordlenedit:wordlen:1] + '-' + word[0:wordlenedit:1] + 'ay'
return output
However this function can be written in a much more concise/simple way, using Regular Expressions, like this:
import re
def pyglatin3(word):
# Get the first index of one of these: a, e, i, o, u
start = re.search("[aeiou]", word).start()
# Split the word
return word[start:] + "-" + word[0:start] + "ay"
If you want to do this without using regular expressions, the simplest way is to use enumerate:
def pyglatin(word):
for i, ch in enumerate(word):
if ch in 'aeiou':
return word[i:] + '-' + word[:i] + 'ay'

Categories